<?php
// +----------------------------------------------------------------------
// | ReviewRequest 类型服务
// +----------------------------------------------------------------------
// | 主要服务于ReviewRequest数据处理
// +----------------------------------------------------------------------
// | 错误编码头 215xxx
// +----------------------------------------------------------------------


namespace common\service;


use common\exception\LogicException;
use common\model\CheckListModel;
use common\model\DelayOrderModel;
use common\model\DelayOrderTaskModel;
use common\model\EntityModel;
use common\model\NoteModel;
use common\model\OrderModel;
use common\model\OrderTaskListModel;
use common\model\PlanModel;
use common\model\PlaylistItemVersionModel;
use common\model\ProjectModel;
use common\model\ReviewRequestModel;
use common\model\ReviewRequestNodeModel;
use common\model\StatusModel;
use common\model\StepModel;
use common\model\TaskModel;
use common\model\TaskRepairOrderModel;
use common\model\TaskWorkOrderModel;
use common\model\UserModel;
use common\model\VersionCheckListModel;
use common\model\VersionModel;
use malkusch\lock\mutex\PHPRedisMutex;
use support\bootstrap\Redis;
use support\EntityTaskFilterParser;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\Hook;
use think\module\Module;
use Throwable;
use Webman\Stomp\Client;
use function request;

class ReviewRequestService
{
    /**
     * @var ReviewRequestModel
     */
    private $requestReviewModel;

    /**
     * @var ReviewRequestNodeModel
     */
    private $requestReviewNodeModel;

    private $taskRepairOrderModel;

    use EntityTaskFilterParser;

    // 单例工具
    use SingletonTrait;

    public function __construct()
    {
        $this->requestReviewModel = model(ReviewRequestModel::class);
        $this->requestReviewNodeModel = model(ReviewRequestNodeModel::class);
        $this->taskRepairOrderModel = model(TaskRepairOrderModel::class);
    }

    /**
     * 待审核任务列表
     * @param $param
     * @param $userId
     * @param $tenantId
     * @return array
     * @throws \Exception
     */
    public function myReviewList($param, $userId, $tenantId)
    {
        $filter = $param['filter'] ?? [];
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];
        $projectId = $filter['project_id'] ?? $filter['task.project_id'] ?? 0;
        $extraQueryFields = $param['fields'] ?? "";
        $searchUserName = $filter['executor_name'] ?? "";
        $stepCategoryId = $filter['step_category_id'] ?? 0;
        $stepId = $filter['step_id'] ?? 0;
        $submitTime = $filter['submit_time'] ?? null;
        $reviewTime = $filter['review_time'] ?? null;
        $roleCode = $filter['role_code'] ?? null;
        $moduleCode = $param['module_code'] ?? '';
        $order = $param['order'] ?? "review_request_node.is_reviewed DESC,v.id ASC";

        // 合并模块code筛选
        if (empty($stepCategoryId) && !empty($moduleCode)) {
            $moduleStepCategoryIdList = StepService::getInstance()->getStepCategoryByMergeModuleConfig($moduleCode, true);
            if (!empty($moduleStepCategoryIdList)) {
                $stepCategoryId = ['IN', implode(',', array_column($moduleStepCategoryIdList, 'id'))];
            }
        }

        //审核列表 待审核版本

        $taskModuleData = Module::$moduleDictData['module_index_by_code']['task'];
        $versionModuleData = Module::$moduleDictData['module_index_by_code']['version'];

        $fields = [
            "v.id as version_id",
            "v.number as version_number",
            "v.link_id",
            "v.created_by",
            "v.project_id",
            "v.is_pass v_is_pass",
            "review_request.id as review_request_id",
            "review_request.name",
            "review_request.created",
            "review_request_node.id as review_request_node_id",
            "review_request_node.is_pass",
            "review_request_node.is_reviewed",
            "review_request_node.reviewed",
            "review_request_node.start_at",
            "task.executor",
        ];

        //任务的版本 并且审核人是 $userId 当前流程节点激活状态

        $where = [
            "v.module_id" => $taskModuleData['id'],
            "v.is_deprecate" => 'no',
            "review_request_node.plan_reviewer" => $userId,
            'review_request.tenant_id' => $tenantId,
            "_logic" => "AND"
        ];

        if (isset($roleCode)) {
            $where["review_request_node.role_code"] = $roleCode;
        }

        if (isset($filter['is_reviewed'])) {
            if ($filter['is_reviewed'] == 1) {
                $where['review_request_node.is_reviewed'] = "yes";
            } else {
                $where['review_request_node.is_reviewed'] = "no";
                $where['review_request.is_reviewed'] = "no";
                $where['review_request_node.is_active'] = "yes";
            }
        } else {
            $where[] = [
                ['review_request_node.is_reviewed' => "yes"],
                [
                    "review_request_node.is_reviewed" => "no",
                    "review_request.is_reviewed" => "no",
                    "review_request_node.is_active" => "yes",
                ],
                "_logic" => "OR"
            ];
        }
        unset($filter['is_reviewed'], $filter['executor_name'], $filter['step_id'], $filter['step_category_id'], $filter['task.project_id'], $filter['project_id'], $filter['submit_time'], $filter['review_time'], $filter['module_code']);

        $parsedFilter = $this->parseMultipleEntityTaskFilter($filter);

        $where = array_merge($parsedFilter, $where);
        // 任务工序筛选
        if ($stepId > 0) {
            $where['task.step_id'] = $stepId;
        }

        // 任务工序分类筛选
        if ($stepCategoryId > 0) {
            $where['task.step_category_id'] = $stepCategoryId;
        }

        if ($projectId > 0) {
            // 支持外部项目筛选
            $projectList = model(ProjectModel::class)->where(['belong_project_id' => $projectId])->field('id')->select();
            if (count($projectList)) {
                $where['v.project_id'] = ['IN', implode(',', array_column($projectList, 'id')) . ',' . $projectId];
            } else {
                $where['v.project_id'] = $projectId;
            }
        }

        //搜索版本提交人
        if (!empty($searchUserName)) {
            $userModel = model(UserModel::class);
            $executor = $userModel->where(["name" => ['like', "%{$searchUserName}%"]])->field("id")->select();
            $executor = array_column($executor, "id", "id");
            if (!empty($executor)) {
                $where['v.created_by'] = ["IN", implode(',', $executor)];
            }
        }

        //提交时间筛选
        if (!empty($submitTime)) {
            $where['v.created'] = ["BETWEEN", strtotime($submitTime[0]) . "," . strtotime($submitTime[1])];
        }

        //审核时间筛选
        if (!empty($reviewTime)) {
            $where['review_request_node.reviewed'] = ["BETWEEN", strtotime($reviewTime[0]) . "," . strtotime($reviewTime[1])];
        }

        $total = model(ReviewRequestModel::class)
            ->join("__REVIEW_REQUEST_NODE__ AS review_request_node on review_request.id = review_request_node.review_request_id")
            ->join("version v on v.module_id = {$taskModuleData['id']} and v.id = review_request.link_id and review_request.module_id = {$versionModuleData['id']}")
            ->join("__TASK__ as task on v.link_id = task.id")
            ->join('entity on entity.id = task.entity_id')
            ->join('module on entity.module_id = module.id')
            ->where($where)
            ->count();

        $data = model(ReviewRequestModel::class)
            ->join("__REVIEW_REQUEST_NODE__ AS review_request_node on review_request.id = review_request_node.review_request_id")
            ->join("version v on v.module_id = {$taskModuleData['id']} and v.id = review_request.link_id and review_request.module_id = {$versionModuleData['id']}")
            ->join("__TASK__ as task on v.link_id = task.id")
            ->join('entity on entity.id = task.entity_id')
            ->join('module on entity.module_id = module.id')
            ->where($where)
            ->field($fields)
            ->page($page[0], $page[1])
            ->order($order) //优先显示未审核的 然后是按照提交顺序排序
            ->select();

        $taskIds = array_column($data, 'link_id', 'link_id');

        $checkList = [];
        $checkRelationMap = [];
        $taskData = [];
        if (!empty($taskIds)) {
            $queryFields = [
                "task.name", "task.id", "task.man_hour", "task.actual_man_hour", "task.plan_start_time", "task.plan_end_time", "task.executor", "task.assignee",
                "step.name", "step.id",
                "step_category.name", "step_category.id",
                "entity.id", "entity.code", "entity.name", "entity.module_id", "entity.project_id", "entity.entity_id",
                "entity.entity_module_id", "entity.step_workflow_id", "entity.initial_episode_code", "entity.showings_number", "entity.json",
                "project.id", "project.name",
                "check_list.id", "check_list.step_id", "check_list.step_workflow_id", "check_list.content", "check_list.percentage", "check_list.review_tools",
            ];

            if (!empty($extraQueryFields)) {
                $extraQueryFields = explode(',', $extraQueryFields);
                $queryFields = array_merge($queryFields, $extraQueryFields);
            }


            $queryFields = build_complex_query_fields($queryFields, '__');

            $tasks = model(TaskModel::class)->join("__ENTITY__ on task.entity_id = entity.id", "LEFT")
                ->join("__STEP__ ON step.id = task.step_id", 'LEFT')
                ->join("__PROJECT__ ON project.id = task.project_id", "LEFT")
                ->join("__STEP_CATEGORY__ ON task.step_category_id = step_category.id", "LEFT")
                ->join("__CHECK_LIST__ ON check_list.step_id = task.step_id AND check_list.step_workflow_id = entity.step_workflow_id", "LEFT")
                ->where([
                    "task.id" => ["IN", implode(',', $taskIds)],
                ])
                ->field(implode(',', $queryFields))
                ->select();

            unset($field);
            $checkRelationMap = [];
            $filterEntityIdList = [];
            $filterEpisodes = [];
            $executorIdList = array_column($tasks, 'task__executor', 'task__executor');

            if (count($executorIdList) > 0) {
                $executorUserList = model(UserModel::class)->where(['id' => ['IN', implode(',', $executorIdList)]])->field('id,name,union_id,avatar')->select();
                $executorUserList = array_column($executorUserList, null, 'id');
            }
            foreach ($tasks as $task) {
                $tmp = separate_complex_query_data($task, "__");
                $checkList[md5($tmp["check_list"]['step_id'] . $tmp['check_list']['step_workflow_id'])][$tmp["check_list"]['id']] = $tmp['check_list'];

                $checkRelationMap[$tmp["check_list"]['id']] = md5($tmp["check_list"]['step_id'] . $tmp['check_list']['step_workflow_id']);
                $taskData[$task["task__id"]] = $tmp;
                if (!in_array($tmp['entity']['entity_id'], $filterEntityIdList)) {
                    $filterEntityIdList[] = $tmp['entity']['entity_id'];
                }
                if (!empty($tmp['entity']['initial_episode_code']) &&
                    (!array_key_exists($tmp['entity']['project_id'], $filterEpisodes) || !in_array($tmp['entity']['initial_episode_code'], $filterEpisodes[$tmp['entity']['project_id']]))
                ) {
                    $filterEpisodes[$tmp['entity']['project_id']][] = $tmp['entity']['initial_episode_code'];
                }
            }
            $relationEntityMap = [];
            if (count($filterEntityIdList) > 0) {
                $relationEntityMap = model(EntityModel::class)
                    ->where(['id' => ['IN', implode(',', $filterEntityIdList)]])
                    ->field("id,name,code,json,module_id")
                    ->select();
                $relationEntityMap = array_column($relationEntityMap, null, 'id');
                $relationEntityMap = array_map(function ($entityItem) {
                    return array_merge($entityItem, json_decode($entityItem['json'], true) ?? []);
                }, $relationEntityMap);
            }

            // 集查询
            $episodeMap = [];
            if (count($filterEpisodes) > 0) {
                $episodeQueryFilter = [];
                foreach ($filterEpisodes as $filterEpisodeProjectId => $filterEpisodeCodes) {
                    $episodeQueryFilter[] = [
                        "project_id" => $filterEpisodeProjectId,
                        'module_id' => module_by_code('episode')['id'],
                        "code" => ["IN", implode(',', $filterEpisodeCodes)]
                    ];
                }
                $episodeQueryFilter["_logic"] = "OR";
                $episodeMap = model(EntityModel::class)
                    ->field("id,name,code,project_id")->distinct(true)
                    ->where($episodeQueryFilter)
                    ->select();
                // 集以项目进行分组
                $episodeMap = array_group_by($episodeMap, 'project_id');
                $episodeMap = array_map(function ($episodeList) {
                    return array_column($episodeList, null, 'code');
                }, $episodeMap);
            }

            unset($tasks);
            foreach ($taskData as &$taskItem) {
                $taskItem['id'] = $taskItem['task']['id'];
                $taskItem['entity'] = array_merge($taskItem['entity'], json_decode($taskItem['entity']['json'], true) ?? []);
                unset($taskItem['entity']['json']);
//                $taskItem['task']['plan_start_time'] = get_format_date($taskItem['task']['plan_start_time'], 1);
//                $taskItem['task']['plan_end_time'] = get_format_date($taskItem['task']['plan_end_time'], 1);
                $relationModule = Module::$moduleDictData['module_index_by_id'][$taskItem['entity']['entity_module_id']] ?? null;
                if (!empty($relationModule)) {
                    $taskItem[$relationModule['code']] = $relationEntityMap[$taskItem['entity']['entity_id']] ?? null;
                }
                $taskItem['episode'] = $episodeMap[$taskItem['entity']['project_id']][$taskItem['entity']['initial_episode_code']] ?? [
                    'id' => null,
                    'name' => null,
                    'code' => null,
                ];
            }
            $taskData = array_column($taskData, null, 'id');
            // checklist 按照时间进行排序
            foreach ($checkList as &$checkListChannel) {
                $checkListChannel = array_sort_by($checkListChannel, 'percentage');
            }
        }

        //提交人信息
        $versionCreatedByIds = array_column($data, 'created_by', 'created_by');
        $versionCreatedByIds = array_filter($versionCreatedByIds, function ($item) {
            return (int)$item > 0;
        });

        $createdUserData = [];
        if (!empty($versionCreatedByIds)) {
            $userModel = model(UserModel::class);
            $createdUserData = $userModel
                ->where(['id' => ["IN", implode(',', $versionCreatedByIds)]])
                ->field("id,name,email,phone,avatar,union_id")->select();
            $createdUserData = array_column($createdUserData, null, 'id');
        }

        //审核点查询
        $checkListIds = array_column($data, 'version_id', 'version_id');
        $versionCheckListData = [];
        if (count($checkListIds) > 0) {
            $versionCheckListData = model(VersionCheckListModel::class)->where(['version_id' => ['IN', implode(',', $checkListIds)]])->select();
            $versionCheckListData = array_group_by($versionCheckListData, 'version_id');
        }

        foreach ($data as &$item) {
            $versionCheckList = $versionCheckListData[$item['version_id']] ?? [];

            $tmpData = [
                'version' => [
                    'id' => $item['version_id'],
                    'number' => $item['version_number'],
                    'link_id' => $item['link_id'],
                    'created_by' => $item['created_by'],
                    'is_pass' => $item['v_is_pass'],
                ],
                'version_check_list' => $versionCheckList,
                'review_request' => [
                    'id' => $item['review_request_id'],
                    'name' => $item['name'],
                    'created' => $item['created'],
                ],
                'review_request_node' => [
                    'id' => $item['review_request_node_id'],
                    'is_pass' => $item['is_pass'],
                    'is_reviewed' => $item['is_reviewed'],
                    'reviewed' => $item['reviewed'],
                    'start_at' => $item['start_at'],
                ],
                'tags' => [
                    [
                        'id' => $item['version_id'],
                        'name' => "v" . $item['version_number'],
                        'type' => "version",
                    ],
                ],
            ];
            foreach ($versionCheckList as $checkListPoint) {
                $tmpData['tags'][] = [
                    'id' => $checkListPoint['id'],
                    'name' => $checkListPoint['content'],
                    'type' => 'check_list',
                ];
            }

            $taskId = $item['link_id'];
            if (isset($taskData[$taskId])) {
                $tmpData = array_merge($tmpData, $taskData[$taskId]);
            }

            if (isset($createdUserData[$item['created_by']])) {
                $tmpData['created_by'] = $createdUserData[$item['created_by']];
            }
            $tmpData['executor'] = $executorUserList[$item['executor']] ?? null;

            try {
                //计算 checklist 进度
                $checkListId = $tmpData['version_check_list'][0]['check_list_id'];
                $relationKey = $checkRelationMap[$checkListId];
                $checkListData = $checkList[$relationKey] ?? [];
                $tmpVersionCheckMap = array_column($tmpData['version_check_list'], 'check_list_id', 'check_list_id');
                $checkMaxIndex = 0;
                $index = 0;
                foreach ($checkListData as $checkPointIndex => $checkPoint) {
                    if (in_array($checkPoint['id'], $tmpVersionCheckMap)) {
                        $checkMaxIndex = $index;
                    }
                    ++$index;
                }
                $checkListIndex = $checkMaxIndex + 1;
                $tmpData['check_list'] = array_values($checkListData);
                $tmpData['check_list_progress'] = [
                    'now' => $checkListIndex,
                    'total' => count($checkListData)
                ];
            } catch (Throwable $e) {
                // todo 如果check_list 发生变动 可能会产生 找不到下标
                $tmpData['check_list_progress'] = [
                    'now' => 1,
                    'total' => 1
                ];
            }
            unset($tmpData['id']);
            $item = $tmpData;
        }

        return ['total' => $total, 'rows' => $data];
    }

    /**
     * 提交审批申请
     * @param $data
     * @return array
     * @throws Throwable
     */
    public function create($data)
    {
        $reviewersData = $data['reviewers'];
        $reviewRequestData = $data['data'];

        $nodesData = [];
        $parentId = 0;
        $reviewerActivated = false;

        $isPassAll = true;

        // 校验是否申请过延期
        if (!empty($data['data']['link_id'])
            && !empty($data['data']['param']['task_delay_time'])
            && !empty($data['module_id'])
            && $data['module_id'] == module_by_code('task')['id']
        ) {
            $this->checkDelay($data['data']['link_id']);
        }

        foreach ($reviewersData as $key => $reviewer) {
            $skip = $reviewer['skip'];
            // 第一个节点并且没有跳过的节点
            // 不需要跳过得第一个节点 必须要激活
            $isActive = "no";
            if ($key == 0 && !$skip || !$skip && !$reviewerActivated) {
                $reviewerActivated = true;
                $isActive = "yes";
            }
            // 是否全部跳过判断标识
            if (!$skip) {
                $isPassAll = false;
            }
            $tmp = [
                'role_code' => $reviewer['role_code'],
                'plan_reviewer' => $reviewer['user_id'],
                'real_reviewer' => $skip ? $reviewer['user_id'] : 0,
                'is_pass' => $skip ? "yes" : "no", //是否通过  跳过的直接自动通过
                'is_reviewed' => $skip ? "yes" : "no", //默认都没有审核
                'is_active' => $isActive, //激活状态
                'start_at' => $isActive === 'yes' ? time() : 0,
                'reviewed' => $skip ? time() : 0,
                'is_second_confirm' => $skip ? 'yes' : 'no'
            ];
            if (!empty($reviewer['param'])) {
                $tmp['param'] = $reviewer['param'];
            }
            if (isset($reviewer['confirm_end_time'])) {
                $tmp['confirm_end_time'] = $reviewer['confirm_end_time'];
            }
            $nodesData[] = $tmp;
        }
        //当前所有节点都跳过就直接通过审批
        if ($isPassAll) {
            $reviewRequestData['is_reviewed'] = "yes";
            $reviewRequestData['reviewed'] = time();
        }

        $reviewRequestData['is_pass'] = $isPassAll ? "yes" : "no";

        $this->requestReviewModel->startTrans();
        try {
            $reviewRequest = $this->requestReviewModel->addItem($reviewRequestData);
            if (!$reviewRequest) {
                throw new LogicException($this->requestReviewModel->getError(), ErrorCode::REVIEW_ADD_FAILURE);
            }
            $res['review_request'] = $reviewRequest;
            $res['nodes'] = [];
            foreach ($nodesData as $nodeData) {

                $nodeData['review_request_id'] = $reviewRequest['id'];
                $nodeData['parent_id'] = $parentId;
                $node = $this->requestReviewNodeModel->addItem($nodeData);
                if (!$node) {
                    throw new LogicException($this->requestReviewNodeModel->getError(), ErrorCode::REVIEW_ADD_FAILURE);
                }

                $res['nodes'][] = $node;
                $parentId = $node['id'];
            }
            $this->afterReviewRequestCreated($reviewRequest, $res['nodes']);

            if ($isPassAll) {
                $reviewRequest = $this->requestReviewModel->find($reviewRequest['id']);
                $this->afterReviewedFinished($reviewRequest);
            }
            $this->requestReviewModel->commit();
            return $res;
        } catch (Throwable $e) {
            $this->requestReviewModel->rollback();
            throw $e;
        }

    }

    /**
     * 校验是否申请过延期
     * @param $taskId
     * @return array
     */
    public function checkDelay($taskId)
    {
        if (empty($taskId)) {
            return [];
        }
        $taskDelay = model(ReviewRequestModel::class)
            ->where(['module_id' => module_by_code('task')['id'], 'link_id' => $taskId, 'is_pass' => 'no', 'is_reviewed' => 'no'])
            ->field('link_id,module_id,is_pass,name,param')
            ->find();
        if (!empty($taskDelay)) {
            throw new LogicException('delay already apply', ErrorCode::DELAY_ALREADY_APPLY);
        }
    }


    /**
     * 校验是否申请过延期s
     * @param $taskIds
     * @return array|mixed|string
     */
    public function checkDelays($taskIds)
    {
        if (empty($taskIds)) {
            return [];
        }
        $taskDelay = model(ReviewRequestModel::class)
            ->where(['module_id' => module_by_code('task')['id'], 'link_id' => ['IN', $taskIds], 'is_pass' => 'no', 'is_reviewed' => 'no'])
            ->field('link_id as task_id')
            ->column('task_id');
        if (empty($taskDelay)) {
            return [];
        }
        return $taskDelay;
    }

    /**
     * 审批
     * @param $data
     * @param $currentUserId
     * @return array
     * @throws Throwable
     */
    public function review($data, $currentUserId)
    {
        $data['is_reviewed'] = "yes";
        $data['is_active'] = "no";
        $data['reviewed'] = time();
        $data['real_reviewer'] = $currentUserId;
        $noteItem = $data['note_item'] ?? [];

        $node = $this->requestReviewNodeModel->find($data['id']);
        $reviewRequest = $this->requestReviewModel->find($node['review_request_id']);

        //审核过的不能再审核
        if ($reviewRequest['is_reviewed'] === 'yes') {
            throw new LogicException("review request review done", ErrorCode::REVIEW_REQUEST_REVIEW_DONE);
        }

        // 处理审核意见数据
        $this->dealReviewNoteData($reviewRequest, $node, $data, $noteItem);

        $requestReviewNodeModel = model(ReviewRequestNodeModel::class);
        //下一步
//        $nextChild = $this->requestReviewNodeModel->where(['parent_id' => $data['id']])->find();

        $res = [];
        $requestReviewNodeModel->startTrans();
        try {
            $flag = $requestReviewNodeModel->modifyItem($data);
            if (!$flag) {
                throw new LogicException($requestReviewNodeModel->getError(), $requestReviewNodeModel->getErrorCode());
            }
            //添加反馈
            if (!empty($noteItem)) {
                NoteService::getInstance()->createNote($noteItem);
            }
            $res['changed'] = $flag;
            $this->afterReviewRequestNodeReviewed($flag);
            $requestReviewNodeModel->commit();
        } catch (Throwable $e) {
            $requestReviewNodeModel->rollback();
            throw $e;
        }
        return $res;
    }

    /**
     * 批量审核
     * @param $data
     * @param $userId
     * @return void
     * @throws Throwable
     */
    public function batchReview($data, $userId)
    {
        try {
            foreach ($data as $item) {
                $this->review($item, $userId);
            }
        } catch (LogicException $e) {
            throw_strack_exception($e->getMessage(), $e->getCode());
        }
    }

    /**
     * 筛选出所有下游任务
     * @param $taskList
     * @param array $downStreamMap
     * @param $currentTask
     * @param array $downstreamTaskList
     */
    private function findAllDownstreamTask($taskList, array $downStreamMap, $currentTask, array &$downstreamTaskList)
    {
        if (!empty($downStreamMap[$currentTask['step_id']])) {
            foreach ($downStreamMap[$currentTask['step_id']] as $downStepId) {
                if (empty($taskList[$downStepId])) {
                    continue;
                }
                foreach ($taskList[$downStepId] as $task) {
                    if (array_key_exists($task['id'], $downstreamTaskList)) {
                        continue;
                    }
                    $downstreamTaskList[$task['id']] = $task;
                    $this->findAllDownstreamTask($taskList, $downStreamMap, $task, $downstreamTaskList);
                }
            }
        }
    }

    /**
     * 审批结束处理
     * @param array $requestReview
     * @throws Exception
     * @throws Throwable
     */
    private function afterReviewedFinished($requestReview)
    {
        $module = Module::$moduleDictData['module_index_by_id'][$requestReview['module_id']];
        $latestReviewedRequestReviewNode = $this->requestReviewNodeModel->where(['review_request_id' => $requestReview['id'], 'is_reviewed' => 'yes'])->order("id DESC")->find();
        $latestReviewedRequestReviewer = UserService::getInstance()->getUserFindField(['id' => $latestReviewedRequestReviewNode['plan_reviewer']], '*');
        switch ($module['code']) {
            case "version":
                //关联的版本
                /** @var VersionModel $versionModel */
                $versionModel = model(VersionModel::class);
                $version = $versionModel->where(['id' => $requestReview['link_id']])->field("id,project_id,link_id,module_id,tenant_id")->find();
                if (empty($version)) {
                    break;
                }
                //修改版本状态
                $vuFlag = $versionModel->modifyItem(['id' => $version['id'], 'is_pass' => $requestReview['is_pass']]);
                if (!$vuFlag) {
                    throw new LogicException($versionModel->getError(), ErrorCode::VERSION_MODIFY_FAILURE);
                }
                $versionService = VersionService::getInstance();
                $versionService->afterVersionReviewed($version, $requestReview, $requestReview['is_pass'] == "yes");
                break;
            case "order":
                //关联的订单
                /** @var OrderModel $orderModel */
                $orderModel = model(OrderModel::class);
                $order = $orderModel->where(['id' => $requestReview['link_id']])->field("id")->find();
                if (empty($order)) {
                    break;
                }
                //修改订单状态 等待乙方确认

                $status = $requestReview['is_pass'] == "yes" ? "wait_for_party_b_ensure" : "party_a_review_deny";
                $vuFlag = $orderModel->modifyItem(['id' => $order['id'], 'status' => $status]);
                if (!$vuFlag) {
                    throw new Exception($orderModel->getError(), ErrorCode::ORDER_MODIFY_FAILURE);
                }
                if ($requestReview['is_pass'] == "yes") {
                    // 通知乙方确认订单
                    try {
                        $hookData = [
                            'type' => 'order_review_result_outsource',
                            'data' => [
                                'order_id' => $order['id'],
                            ],
                        ];
                        Hook::listen('review_request_finished_after', $hookData);
                    } catch (Throwable $e) {
                        trace(format_exception_info($e), 'ERR');
                    }
                }

                // 通知甲方订单审批结果
                try {
                    $hookData = [
                        'type' => 'order_review_result',
                        'data' => [
                            'order_id' => $order['id'],
                            'is_pass' => $requestReview['is_pass'] == "yes",
                        ],
                    ];
                    Hook::listen('review_request_finished_after', $hookData);
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');

                }
                break;
            case "settlement":
                // 关联的结算

                $financeService = new FinanceService();
                $financeService->handleSettlementReviewed($requestReview['link_id'], $requestReview['is_pass'] == "yes");
                try {
                    $financeService->notifyReviewSettlementResult($requestReview, $requestReview['is_pass'] == 'yes');
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
                if ($requestReview['is_pass'] == 'yes') {
                    try {
                        Client::send("create_order_settlement_chat", build_queue_data_with_xu([
                            'settlement_id' => $requestReview['link_id']
                        ]));
                    } catch (Throwable $e) {
                        trace(format_exception_info($e), 'ERR');
                    }
                }
                break;
            case "task_repair_order":
                // 关联的任务返修单
                try {
                    $requestReviewNode = $this->requestReviewNodeModel->where(['review_request_id' => $requestReview['id']])->order("id DESC")->find();
                    $reviewParam = json_decode($requestReviewNode['param'] ?? '{}', true);
                    $taskRepairStepCategoryId = $reviewParam['repair_step_category_id'] ?? 0;
                    $taskRepairOrderService = new TaskRepairOrderService();
                    $taskRepairOrderService->handleRepairOrderReviewed($requestReview['link_id'], $requestReview['is_pass'] == "yes", $taskRepairStepCategoryId);

                    // 最后一个审核人
//                    $requestReviewNode = $this->requestReviewNodeModel->where(['review_request_id' => $requestReview['id']])->order("id DESC")->find();
//                    try {
//                        $taskRepairOrderService->notifyReviewRepairOrderResult($requestReview['link_id'], $requestReview['is_pass'] == "yes", $requestReviewNode);
//                    } catch (\Throwable $e) {
//                        trace(format_exception_info($e), 'ERR');
//                        // 通知逻辑不throw
//                    }
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                    throw $e;
                }

                break;
            // 实体修改审核监听
            case 'design':
            case 'storyboard':
                /**
                 * 修改实体信息  同时根据提交时指定的状态 来进行操作
                 * 监听分镜和概念的修改审核操作
                 */
                $param = json_decode($requestReview['param'], true);

                if ($requestReview['is_pass'] === 'yes') {
                    $entityStatusCode = $param['pass_status_code'];
                } else {
                    $entityStatusCode = $param['deny_status_code'];
                }
                $entityStatus = model(StatusModel::class)->where(['code' => $entityStatusCode])->find();
                if (empty($entityStatus)) {
                    throw_strack_exception("missing status $entityStatusCode", ErrorCode::MISSING_STATUS);
                }
                $module = Module::$moduleDictData['module_index_by_id'][$requestReview['module_id']];
                $newData = $param['new'];
                $newData[$module['code'] . '_status'] = $entityStatus['id'];
                $cService = CommonService::instance('entity');
                $cService->update($newData, $module['code']);
                break;

            case 'plan':
                // 排期确认完成
                $hookData = [
                    'type' => 'plan_review_result',
                    'data' => [
                        'review_request' => $requestReview,
                        'review_request_node' => $latestReviewedRequestReviewNode,
                        'reviewer' => $latestReviewedRequestReviewer,
                    ],
                ];
                Hook::listen('review_request_finished_after', $hookData);
                break;
            case 'task':
                // 任务延期
                $fields = [
                    'entity.initial_episode_code', 'entity.showings_number', 'entity.name', 'entity.module_id',
                    'task.name',
                ];
                $taskEntity = model(TaskModel::class)
                    ->join('entity on task.entity_id = entity.id', 'LEFT')
                    ->where(['task.id' => $requestReview['link_id']])
                    ->field(build_complex_query_fields($fields, '__'))
                    ->find();
                if (!empty($taskEntity)) {
                    // 修改计划完成时间
                    try {
                        $param = json_decode($requestReview['param'], true);
                        $taskData = [
                            'id' => $requestReview['link_id'],
                            'plan_end_time' => date('Y-m-d H:i:s', $param['task_delay_time'])
                        ];
                        if (isset($param['task_delay_start_time'])) {
                            $taskData['plan_start_time'] = date('Y-m-d H:i:s', $param['task_delay_start_time']);
                        }
                        if ($requestReview['is_pass'] == 'yes') {
                            $this->delayRequestTaskUpdateDelayTime($taskData);
                        }
                    } catch (Throwable $e) {
                        trace(format_exception_info($e), 'ERR');
                    }
                    $hookData = [
                        'type' => 'task_delay_review_result',
                        'data' => [
                            'task_entity' => separate_complex_query_data($taskEntity, '__'),
                            'review_request' => $requestReview,
                            'review_request_node' => $latestReviewedRequestReviewNode,
                            'reviewer' => $latestReviewedRequestReviewer,
                        ],
                    ];
                    Hook::listen('review_request_finished_after', $hookData);
                }
                break;
//            case 'delay_order':
//                // 任务延期
//                $delayOrder = model(DelayOrderModel::class)->find($requestReview['link_id']);
//                if (!empty($delayOrder)) {
//                    if ($requestReview['is_pass'] == 'yes') {
//                        $this->delayRequestDelayOrderUpdateDelayTime($delayOrder);
//                    }
//
//                    $isPassString = $requestReview['is_pass'] == 'yes' ? '已通过' : '未通过';
//                    $messageParam = [
//                        'first' => '延期单' . $isPassString,
//                        'delay_order_name' => $delayOrder['name'],
//                        'reviewer_name' => $latestReviewedRequestReviewer['name'],
//                        'review_at' => date("Y/m/d H:i", $latestReviewedRequestReviewNode['reviewed']),
//                        'remark' => '请及时查看',
//                        'delay_order_id' => $requestReview['link_id'],
//                        'review_request_id' => $requestReview['id'],
//                        'review_request_node_id' => $latestReviewedRequestReviewNode['id']
//                    ];
//                    $messageTemplateId = ReviewRequestMessageService::getInstance()->delayOrderResultMessageTemplateId();
//                    $creator = UserService::getInstance()->getUserFindField(['id' => $requestReview['created_by']], '*');
//                    Client::send('send_notify_message_v2', build_queue_data_with_xu([
//                        "param" => $messageParam,
//                        'receiver' => $creator['union_id'],
//                        'template_id' => $messageTemplateId,
//                        'content_type' => 'card_message',
//                        'notice_type' => 'examine',
//                        'is_popup' => 1,
//                        'message_key' => 'task_delay_order_review_result',
//                    ]));
//                }
//                break;
            case 'delay_order_task':
                $data = [
                    'review_request' => $requestReview,
                    'review_request_node' => $latestReviewedRequestReviewNode,
                ];
                Client::send("delay_order_task_review", build_queue_data_with_xu($data));
                break;
        }

    }

    /**
     * 提交的审核列表
     * @param $params
     * @return array
     * @throws \Exception
     */
    public function selectMySubmittedReviewList($params)
    {
        $param = $params['param'] ?? [];
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];
        $projectId = $param['filter']['project_id'] ?? 0;
        $extraQueryFields = $param['fields'] ?? "";

        $submitTime = $param['filter']['submit_time'] ?? null;
        $reviewTime = $param['filter']['review_time'] ?? null;

        $reviewedFilter = $param['filter']['is_reviewed'] ?? null;


        //审核列表 待审核版本
        $versionModel = model(VersionModel::class);

        $taskModuleData = Module::$moduleDictData['module_index_by_code']['task'];
        $versionModuleData = Module::$moduleDictData['module_index_by_code']['version'];

        $fields = [
            "v.id as version_id",
            "v.number as version_number",
            "v.link_id",
            "v.created_by",
            "v.project_id",
            "v.is_pass v_is_pass",
            "rr.id as rr_id",
            "rr.name",
            "rr.created",
            "rr.reviewed",
            "rr.is_reviewed",
            "rr.is_pass",
        ];

        //任务的版本 并且审核人是 $userId 当前流程节点激活状态

        $userId = request()->getUserId();

        $where = [
            "v.module_id" => $taskModuleData['id'],
            "v.created_by" => $userId,
            "_logic" => "AND"
        ];


        if ($reviewedFilter) {
            $where['rr.is_reviewed'] = $reviewedFilter;
        }
        if ($projectId > 0) {
            $where['v.project_id'] = $projectId;
        }

        //提交时间筛选
        if (!empty($submitTime)) {
            $where['v.created'] = ["BETWEEN", strtotime($submitTime[0]), strtotime($submitTime[1])];
        }

        //审核时间筛选
        if (!empty($reviewTime)) {
            $where['rr.reviewed'] = ["BETWEEN", strtotime($reviewTime[0]), strtotime($reviewTime[1])];
        }

        $total = $versionModel
            ->alias("v")
            ->join("__REVIEW_REQUEST__ AS rr ON v.id=rr.link_id AND rr.module_id = {$versionModuleData['id']}", "LEFT")
            ->where($where)
            ->count();

        $data = $versionModel
            ->alias("v")
            ->join("__REVIEW_REQUEST__ AS rr ON v.id=rr.link_id AND rr.module_id = {$versionModuleData['id']}", "LEFT")
            ->join("__VERSION_CHECK_LIST__ AS vcl ON v.id=vcl.version_id", "LEFT")
            ->where($where)
            ->field($fields)
            ->page($page[0], $page[1])
            ->order("rr.is_reviewed DESC,rr.is_pass DESC,rr.reviewed desc,v.id ASC") //优先显示未审核的 然后是按照提交顺序排序
            ->select();

        $checkRelationMap = [];

        $taskIds = array_column($data, 'link_id', 'link_id');
        $taskData = [];
        $checkList = [];
        if (!empty($taskIds)) {
            $queryFields = [
                "task.name",
                "task.id",
                "task.man_hour",
                "task.actual_man_hour",
                "step.name",
                "step.id",
                "step_category.name",
                "step_category.id",
                "entity.id",
                "entity.code",
                "entity.name",
                "entity.module_id",
                "project.id",
                "project.name",
                "check_list.id",
                "check_list.step_id",
                "check_list.step_workflow_id",
                "check_list.content",
                "check_list.percentage",
                "check_list.review_tools",
            ];

            if (!empty($extraQueryFields)) {
                $extraQueryFields = explode(',', $extraQueryFields);
                $queryFields = array_merge($queryFields, $extraQueryFields);
            }

            $taskModel = model(TaskModel::class);
            $resTask = $taskModel->selectData(
                [
                    "filter" => [
                        "task.id" => ["IN", implode(',', $taskIds)],
                    ],
                    "fields" => implode(',', $queryFields)
                ]
            );
            $taskData = $resTask['rows'];
            foreach ($taskData as &$taskItem) {
                $taskItem['id'] = $taskItem['task']['id'];
                $checkList[md5($taskItem["check_list"]['step_id'] . $taskItem['check_list']['step_workflow_id'])][$taskItem["check_list"]['id']] = $taskItem['check_list'];
                $checkRelationMap[$taskItem["check_list"]['id']] = md5($taskItem["check_list"]['step_id'] . $taskItem['check_list']['step_workflow_id']);

            }
            $taskData = array_column($taskData, null, 'id');
        }

        //提交人信息
        $versionCreatedByIds = array_column($data, 'created_by', 'created_by');
        $versionCreatedByIds = array_filter($versionCreatedByIds, function ($item) {
            return (int)$item > 0;
        });

        $createdUserData = [];
        if (!empty($versionCreatedByIds)) {
            $userModel = model(UserModel::class);
            $createdUserData = $userModel
                ->where(['id' => ["IN", implode(',', $versionCreatedByIds)]])
                ->field("id,name,email,phone,avatar,union_id")->select();
            $createdUserData = array_column($createdUserData, null, 'id');
        }

        //每个任务的CheckList
        $stepIds = array_column(array_column($taskData, 'step'), 'id', 'id');
        $checkListModel = model(CheckListModel::class);
        $checkListData = $checkListModel->where(['step_id' => ['IN', implode(',', $stepIds)]])->select();
        $checkListData = array_group_by($checkListData, 'step_id');
        $checkListData = array_map(function ($item) {
            $item = array_sort_by($item, 'percentage', 'asc');
            return array_flip(array_column($item, 'id'));
        }, $checkListData);

        //审核点查询

        $checkListIds = array_column($data, 'version_id', 'version_id');
        $versionCheckListData = model(VersionCheckListModel::class)->where(['version_id' => ['IN', implode(',', $checkListIds)]])->select();
        $versionCheckListData = array_group_by($versionCheckListData, 'version_id');

        foreach ($data as &$item) {
            $versionCheckList = $versionCheckListData[$item['version_id']] ?? [];

            $tmpData = [
                'version' => [
                    'id' => $item['version_id'],
                    'number' => $item['version_number'],
                    'link_id' => $item['link_id'],
                    'created_by' => $item['created_by'],
                    'is_pass' => $item['v_is_pass'],
                ],
                'version_check_list' => $versionCheckList,
                'review_request' => [
                    'id' => $item['rr_id'],
                    'name' => $item['name'],
                    'created' => $item['created'],
                    'is_pass' => $item['is_pass'],
                    'is_reviewed' => $item['is_reviewed'],
                    'reviewed' => $item['reviewed'],
                ],
                'tags' => [
                    [
                        'id' => $item['version_id'],
                        'name' => "v" . $item['version_number'],
                        'type' => "version",
                    ],
                ],
            ];


            foreach ($versionCheckList as $checkListPoint) {
                $tmpData['tags'][] = [
                    'id' => $checkListPoint['id'],
                    'name' => $checkListPoint['content'],
                    'type' => 'check_list',
                ];
            }

            $taskId = $item['link_id'];
            if (isset($taskData[$taskId])) {
                $tmpData = array_merge($tmpData, $taskData[$taskId]);
            }

            if (isset($createdUserData[$item['created_by']])) {
                $tmpData['created_by'] = $createdUserData[$item['created_by']];
            }

            //checklist 进度
            try {
                //计算 checklist 进度
                $checkListId = $tmpData['version_check_list'][0]['check_list_id'];
                $relationKey = $checkRelationMap[$checkListId];
                $checkListData = $checkList[$relationKey] ?? [];
                $tmpVersionCheckMap = array_column($tmpData['version_check_list'], 'check_list_id', 'check_list_id');
                $checkMaxIndex = 0;
                $index = 0;
                foreach ($checkListData as $checkPointIndex => $checkPoint) {
                    if (in_array($checkPoint['id'], $tmpVersionCheckMap)) {
                        $checkMaxIndex = $index;
                    }
                    ++$index;
                }
                $checkListIndex = $checkMaxIndex + 1;
                $tmpData['check_list'] = array_values($checkListData);
                $tmpData['check_list_progress'] = [
                    'now' => $checkListIndex,
                    'total' => count($checkListData)
                ];
            } catch (Throwable $e) {
                // todo 如果check_list 发生变动 可能会产生 找不到下标
                $tmpData['check_list_progress'] = [
                    'now' => 1,
                    'total' => 1
                ];
                trace(format_exception_info($e), 'ERR');
            }
            unset($tmpData['id']);
            $item = $tmpData;
        }

        return ['total' => $total, 'rows' => $data];
    }

    /**
     * 待审核列表
     * @param $param
     * @param $userId
     * @return mixed
     * @throws Exception
     */
    public function reviewList($param, $userId): array
    {
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];
        $reviewTime = $param['filter']['review_time'] ?? null;
        $isReviewed = $param['filter']['is_reviewed'] ?? null;
        unset($param['filter']['review_time'], $param['filter']['is_reviewed']);
        $moduleCode = $param['module_code'] ?? 'settlement';
        $moduleData = Module::$moduleDictData['module_index_by_code'][$moduleCode];
        $queryFields = array_keys(Module::$moduleDictData['field_index_by_code'][$moduleCode]['fixed']);
        $queryFields = array_map(function ($item) use ($moduleCode) {
            return $moduleCode . "." . $item;
        }, $queryFields);
        $queryFields = $param['fields'] ?? $queryFields;
        $moduleExtraQueryFields = $param['extra_query_fields'] ?? "";

        $reviewRequestFields = array_keys(Module::$moduleDictData['field_index_by_code']['review_request']['fixed']);
        $reviewRequestFields = array_map(function ($item) {
            return "review_request." . $item;
        }, $reviewRequestFields);

        $reviewRequestNodeFields = array_keys(Module::$moduleDictData['field_index_by_code']['review_request_node']['fixed']);
        $reviewRequestNodeFields = array_map(function ($item) {
            return "review_request_node." . $item;
        }, $reviewRequestNodeFields);

        $where = $param['filter'];
        // 检查是否自定义字段筛选
        $customKeys = array_keys(Module::$moduleDictData['field_index_by_code'][$moduleCode]['custom'] ?? []);
        foreach ($where as $whereField => $whereValue) {
            if (strstr($whereField, '.') !== false) {
                $moduleField = explode('.', $whereField)[1];
                if (in_array($moduleField, $customKeys)) {
                    $where["JSON_UNQUOTE(JSON_EXTRACT({$moduleCode}.json,'$.{$moduleField}'))"] = $whereValue;
                    unset($where[$whereField]);
                }
            }
        }
        //任务的版本 并且审核人是 $userId 当前流程节点激活状态
        $where[] = [
            "review_request_node.plan_reviewer" => $userId,
            "review_request_node.real_reviewer" => $userId,

            "_logic" => "OR"
        ];
        $where[] = ['review_request.tenant_id' => auto_fill_tenant_id()];

        if (!is_null($isReviewed)) {
            if ($isReviewed == 1) {
                $where[] = ['review_request_node.is_reviewed' => "yes"];
            } else {
                $where[] = ['review_request_node.is_reviewed' => "no"];
                $where[] = ['review_request_node.is_active' => "yes"];
            }
        } else {
            $where[] = [
                ['review_request_node.is_reviewed' => "yes"],
                [
                    "review_request_node.is_reviewed" => "no",
                    "review_request_node.is_active" => "yes",
                ],
                "_logic" => "OR"
            ];
        }
        //审核时间筛选
        if (!empty($reviewTime)) {
            $where['review_request_node.reviewed'] = ["BETWEEN", strtotime($reviewTime[0]), strtotime($reviewTime[1])];
        }
        $realTableName = get_module_table_name($moduleData);

        $total = model(ReviewRequestModel::class)
            ->join("$realTableName AS {$moduleData['code']} on {$moduleData['code']}.id = review_request.link_id AND review_request.module_id={$moduleData['id']}")
            ->join("review_request_node  ON review_request.id = review_request_node.review_request_id")
            ->where($where)
            ->count();
        $fields = array_merge($queryFields, $reviewRequestFields, $reviewRequestNodeFields);
        $fields = build_complex_query_fields($fields, '__');
        $data = model(ReviewRequestModel::class)
            ->join("$realTableName AS {$moduleData['code']} on {$moduleData['code']}.id = review_request.link_id AND review_request.module_id={$moduleData['id']}")
            ->join("review_request_node  ON review_request.id = review_request_node.review_request_id")
            ->where($where)
            ->field($fields)
            ->page($page[0], $page[1])
            ->order("review_request_node.is_reviewed DESC") //优先显示未审核的
            ->select();
        if (count($data) > 0) {
            $extraData = null;
            if (!empty($moduleExtraQueryFields)) {
                $modulePrimaryIdList = array_column($data, "{$moduleCode}__id");
                if ($moduleData['type'] === 'entity') {
                    $modelName = 'entity';
                } else {
                    $modelName = $moduleData['code'];
                }
                $commonService = CommonService::instance($modelName);
                $commonService->setCurrentModuleCode($moduleCode);
                $extraData = $commonService
                    ->select(['filter' => [
                        "{$moduleCode}.id" => ['IN', implode(',', $modulePrimaryIdList)]
                    ],
                        'fields' => $moduleExtraQueryFields
                    ], $moduleCode);
                if (!empty($extraData['rows'])) {
                    $extraData = $extraData['rows'];
                    foreach ($extraData as &$extraDatum) {
                        $extraDatum['primary_id'] = $extraDatum[$moduleCode]['id'];
                    }
                    $extraData = array_column($extraData, null, 'primary_id');
                }
            }
            $createdByUserIdList = array_column($data, 'review_request__created_by', 'review_request__created_by');
            $userMap = model(UserModel::class)->where(['id' => ['IN', $createdByUserIdList]])->field("json", true)->select();
            $userMap = array_column($userMap, null, 'id');
            foreach ($data as &$item) {
                $extraPrimaryId = $item["{$moduleCode}__id"];
                $item = separate_complex_query_data($item, '__');
                $item['created_by'] = $userMap[$item['review_request']['created_by']] ?? null;
                $extraItem = $extraData[$extraPrimaryId] ?? [];
                $item = array_merge($item, $extraItem);
            }
        }

        return ['total' => $total, 'rows' => $data];
    }

    /**
     * 审核任务列表 通过工序分类分组
     * @param $param
     * @param $userId
     * @param $tenantId
     * @return array|mixed
     * @throws \Exception
     * @deprecated 2021年5月22日
     */
    public function myReviewListGroupByStepCategory($param, $userId, $tenantId): array
    {
        $groupBy = $param['group_by'] ?? "step";
        $param['filter']['is_reviewed'] = $param['filter']['is_reviewed'] ?? 0;

        switch ($groupBy) {
            case "entity":
                $indexKey = "entity_id";
                break;
            case "step":
            default:
                $indexKey = "step_id";
        }
        $resData = $this->myReviewList($param, $userId, $tenantId);

        $rows = $resData['rows'];

        $stepCategoryDict = [];
        $stepDict = [];
        $indexDataMap = [];

        foreach ($rows as $key => &$row) {
            if (empty($row[$groupBy])) {
                // 如果找不到分组的索引数据 那么就跳过本条数据
                // todo 做未分组类目
                unset($rows[$key]);
                continue;
            }
            $row['step_id'] = $row['step']['id'];
            $row['step_category_id'] = $row['step_category']['id'];
            $row['entity_id'] = $row['entity']['id'];
            $stepCategoryDict[$row['step_category_id']] = $row['step_category'];
            $stepDict[$row['step_id']] = $row['step'];
            // 组装二层数据map
            if (!empty($row[$groupBy]) && !isset($indexDataMap[$row[$groupBy]['id']])) {
                $indexDataMap[$row[$groupBy]['id']] = $row[$groupBy];
            }
        }

        // 第一层分组使用 二级分类id
        $rows = array_group_by($rows, 'step_category_id');
        // 第二层分组 通过indexKey
        $rows = array_map(function ($row) use ($indexKey) {
            return array_group_by($row, $indexKey);
        }, $rows);
        $resData['rows'] = [];
        unset($row);
        foreach ($rows as $k1 => $row) {
            $tmp = $stepCategoryDict[$k1];
            foreach ($row as $indexKeyItem => $indexKeyValue) {
                if (!isset($indexDataMap[$indexKeyItem])) {
                    continue;
                }
                $tmp['children'][] = array_merge($indexDataMap[$indexKeyItem], ['children' => $row[$indexKeyItem]]);
            }
            $resData['rows'][] = $tmp;
        }

        return $resData;
    }

    /**
     * 查询审核点审批结果
     * @param $param
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function getReviewResult($param)
    {
        $reviewRequestId = $param['filter']['review_request_id'] ?? 0;

        $versionId = $param['filter']['version_id'];

        if ($reviewRequestId == 0) {
            $versionModule = Module::$moduleDictData['module_index_by_code']['version'];
            $reviewRequest = model(ReviewRequestModel::class)
                ->where(['link_id' => $versionId, 'module_id' => $versionModule['id']])
                ->order("id desc")->find();
            $reviewRequestId = $reviewRequest['id'];
        }
        $reviewRequestNodes = model(ReviewRequestNodeModel::class)->where(['review_request_id' => $reviewRequestId])->order("parent_id")->select();

        $versionCheckList = model(VersionCheckListModel::class)
            ->join("check_list ON check_list.id = version_check_list.check_list_id")
            ->where(['version_check_list.version_id' => $versionId])
            ->field("check_list.*,version_check_list.id as version_check_list_id")
            ->select();

        $reviewRequestNodes = array_map(function ($item) {
            $item['param'] = json_decode($item['param'], true);
            return $item;
        }, $reviewRequestNodes);
        $reviewUserIdArray = array_column($reviewRequestNodes, 'real_reviewer', 'real_reviewer');
        $planReviewUserIdArray = array_column($reviewRequestNodes, 'plan_reviewer', 'plan_reviewer');
        $userIdArray = array_unique(array_merge($planReviewUserIdArray, $reviewUserIdArray));

        $nodes = [];
        $roles = array_column($reviewRequestNodes, 'role_code', 'role_code');
        $roles = teamones_request('teamones-im', 'role/select', ['param' => [
            'filter' => [
                "role.code" => ["-in", implode(',', $roles)],
            ],
        ]])['data']['rows'];
        $roles = array_column($roles, null, 'code');
        $users = model(UserModel::class)->where(['id' => ['IN', implode(',', $userIdArray)]])->field("json", true)->select();
        $users = array_column($users, null, 'id');
        foreach ($reviewRequestNodes as $node) {
            $node['plan_reviewer_user'] = $users[$node['plan_reviewer']] ?? null;
            $node['real_reviewer_user'] = $users[$node['real_reviewer']] ?? $node['plan_reviewer_user'];
            $node['role'] = $roles[$node['role_code']] ?? null;
            if (empty($node['param']) || count($node['param']) == 0) {
                foreach ($versionCheckList as $versionCheck) {
                    $tmpNode = $node;
                    unset($tmpNode['']);
                    $tmpNode['is_pass'] = $node['is_pass'];
                    $nodes[$versionCheck['version_check_list_id']][] = $tmpNode;
                }
                continue;
            }
            foreach ($node['param'] as $checkListResult) {
                $tmpNode = $node;
                unset($tmpNode['']);
                if (!is_array($checkListResult) || count($checkListResult) == 0) {
                    continue;
                }
                if (!isset($checkListResult['is_pass'])) {
                    continue;
                }
                $tmpNode['is_pass'] = $checkListResult['is_pass'];
                $nodes[$checkListResult['version_check_list_id']][] = $tmpNode;
            }
            unset($node['param']);
        }

        foreach ($versionCheckList as &$versionCheck) {
            $versionCheck['review_result'] = $nodes[$versionCheck['version_check_list_id']] ?? [];
        }
        return $versionCheckList;
    }

    /**
     * 检查是否还存在未审核的记录
     * @param $id
     * @param $moduleId
     * @return bool
     */
    public function checkHasReviewNotReviewed($id, $moduleId)
    {
        $r = $this->requestReviewModel->where([
            'link_id' => $id, 'module_id' => $moduleId, 'is_reviewed' => 'no'
        ])->find();
        return !empty($r);
    }

    /**
     * 更新未通过审核之后的状态
     * @param array $reviewRequest
     * @throws \Exception
     */
    public function updateReviewNoPassStatus(array $reviewRequest)
    {
        $module = Module::$moduleDictData['module_index_by_id'][$reviewRequest['module_id']];
        switch ($module['code']) {
            case "version":
                $versionModel = model(VersionModel::class);
                $version = $versionModel->where(['id' => $reviewRequest['link_id']])->field("id,link_id,module_id,tenant_id")->find();
                if (empty($version)) {
                    break;
                }
                //更新任务以及审核列表子项  状态变为处理中
                if ($version['module_id'] === Module::$moduleDictData['module_index_by_code']['task']['id']) {
                    $taskService = TaskService::getInstance();
                    $isOutsideVersion = $version['tenant_id'] !== $reviewRequest['tenant_id'];
                    if ($isOutsideVersion) {
                        $orderService = OrderService::getInstance();
                        $sourceTask = $orderService->getSourceTaskByTaskId($version['link_id']);
                        if (!empty($sourceTask)) {
                            trace('更新外包任务原始任务的审核状态为 pending 待处理', 'DEBUG');
                            model(TaskModel::class)->where(['id' => $sourceTask['id']])->save(['deal_status' => 'pending']);
                            // 更新播放列表子项的状态
                            $plivList = model(PlaylistItemVersionModel::class)->where(['review_request_id' => $reviewRequest['id']])->field('id')->select();
                            if (count($plivList) > 0) {
                                $plivIdList = array_column($plivList, 'id');
                                model(PlaylistItemVersionModel::class)->where(['id' => ['IN', $plivIdList]])->save(['deal_status' => 'pending']);
                            }
                        } else {
                            trace('找不到外包任务的原始任务  外包任务id ' . $version['link_id'], 'ERR');
                        }
                    } else {
                        $taskService->updateTaskDealStatus($version['link_id'], 'pending', $reviewRequest);
                    }
                }
        }
    }

    /**
     * 接受反馈 ( 乙方接受反馈,乙方商务制片接受反馈)
     * @param $reviewRequestNode
     * @throws Exception
     * @throws Throwable
     */
    public function waitFeedbackDeal($reviewRequestNode)
    {
        //当前节点之后的节点后二次确认直接跳过,二次确认通过的状态 审核列表当前人员得以继续往下流转
        $nextReviewRequestNodes = model(ReviewRequestNodeModel::class)
            ->where(['review_request_id' => $reviewRequestNode['review_request_id']])
            ->where(['id' => ['GT', $reviewRequestNode['id']]])
            ->field('id')
            ->select();
        $nextReviewRequestNodeIdList = array_column($nextReviewRequestNodes, 'id');

        //二次确认通过 以及审核反馈接受
        $reviewRequestNodeModel = model(ReviewRequestNodeModel::class);
        $reviewRequestNodeModel->startTrans();
        try {
            //拒绝
            $reviewRequest = $this->requestReviewModel->modifyItem([
                'id' => $reviewRequestNode['review_request_id'],
                'is_pass' => "no",
                'is_reviewed' => "yes",
                'reviewed' => time(),
            ]);
            //审核直接结束 ,状态改为接受反馈
            $reviewRequestNodeModel->save(['id' => $reviewRequestNode['id'], 'is_second_confirm' => 'yes', 'feedback_status' => 'accept_feedback']);

            //更新审核的反馈的状态 ,是否能被展示
            $noteIds = model(NoteModel::class)->where(['review_request_node_id' => $reviewRequestNode['id']])->field('id')->select();
            if (!empty($noteIds)) {
                model(NoteModel::class)->where(['id' => ['IN', array_column($noteIds, 'id')]])->save(['is_feedback_show' => 'yes']);
            }

            //此节点 之后的节点中止 ,被直接结束确认
            if (!empty($nextReviewRequestNodeIdList)) {
                $this->requestReviewNodeModel->where(['id' => ['IN', $nextReviewRequestNodeIdList]])->save(['is_terminate' => 'yes', 'is_second_confirm' => 'yes']);
            }
            $this->afterReviewedFinished($reviewRequest);

            //审核完之后 修改任务状态/修改审核列表子项的处理状态 为以处理
            $version = model(VersionModel::class)->where(['id' => $reviewRequest['link_id']])->field("id,link_id,tenant_id,module_id")->find();
            if (empty($version)) {
                throw new LogicException("version not found", ErrorCode::VERSION_NOT_FOUND);
            }
            $taskService = TaskService::getInstance();
            $isOutsideVersion = $version['tenant_id'] !== $reviewRequest['tenant_id'];
            $taskId = $version['link_id'];
            if ($isOutsideVersion) {
                $sourceTask = OrderService::getInstance()->getSourceTaskByTaskId($version['link_id']);
                if (!empty($sourceTask)) {
                    trace('外包任务审核最终接受结束审核状态为 processed 已处理', 'DEBUG');
                    $taskService->updateTaskDealStatus($sourceTask['id'], 'processed', $reviewRequest);
                } else {
                    trace('找不到外包任务的原始任务  外包任务id ' . $version['link_id'], 'ERR');
                }
                $orderTaskListItem = OrderService::getInstance()->getOrderTaskListItemByRealTaskId($version['link_id']);
                if (!empty($orderTaskListItem)) {
                    model(OrderTaskListModel::class)->modifyItem([
                        'id' => $orderTaskListItem['id'],
                        'deal_status' => 'processed',
                    ]);
                }
            } else {
                $taskService->updateTaskDealStatus($taskId, 'processed', $reviewRequest);
            }

            //工单的 消息提醒  接受反馈 需要提醒给创建方
            $taskWorkOrder = model(TaskWorkOrderModel::class)->where(['review_request_node_id' => $reviewRequestNode['id']])->field('id')->find();
            if (!empty($taskWorkOrder)) {
                TaskWorkOrderService::getInstance()->updateTaskWorkCreatedByUnread($taskWorkOrder['id'], "yes");
            }

            $reviewRequestNodeModel->commit();
        } catch (Throwable $e) {
            $reviewRequestNodeModel->rollback();
            throw $e;
        }
        try {
            // 检查是否需要更新播放列表
            Client::send('check_review_playlist_status', build_queue_data_with_xu(['id' => $reviewRequestNode['id']]));
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 任务返修单审核列表
     * @param array $param
     * @param int $userId
     * @return array
     * @throws Exception
     */
    public function taskRepairOrderReviewList(array $param, int $userId)
    {
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];
        $isReviewed = $param['filter']['is_reviewed'] ?? null;
        unset($param['filter']['review_time'], $param['filter']['is_reviewed']);
        $moduleCode = $param['module_code'] ?? 'settlement';
        $moduleData = Module::$moduleDictData['module_index_by_code'][$moduleCode];
        $queryFields = array_keys(Module::$moduleDictData['field_index_by_code'][$moduleCode]['fixed']);
        $queryFields = array_map(function ($item) use ($moduleCode) {
            return $moduleCode . "." . $item;
        }, $queryFields);
        $queryFields = $param['fields'] ?? $queryFields;
        $moduleExtraQueryFields = $param['extra_query_fields'] ?? "";

        $reviewRequestFields = array_keys(Module::$moduleDictData['field_index_by_code']['review_request']['fixed']);
        $reviewRequestFields = array_map(function ($item) {
            return "review_request." . $item;
        }, $reviewRequestFields);

        $reviewRequestNodeFields = array_keys(Module::$moduleDictData['field_index_by_code']['review_request_node']['fixed']);
        $reviewRequestNodeFields = array_map(function ($item) {
            return "review_request_node." . $item;
        }, $reviewRequestNodeFields);

        $where = $param['filter'] ?? [];
        // 检查是否自定义字段筛选
        $customKeys = array_keys(Module::$moduleDictData['field_index_by_code'][$moduleCode]['custom'] ?? []);
        foreach ($where as $whereField => $whereValue) {
            if (strstr($whereField, '.') !== false) {
                $moduleField = explode('.', $whereField)[1];
                if (in_array($moduleField, $customKeys)) {
                    $where["JSON_UNQUOTE(JSON_EXTRACT({$moduleCode}.json,'$.{$moduleField}'))"] = $whereValue;
                    unset($where[$whereField]);
                }
            }
        }

        //如果序列id 不存在
        if ($moduleCode == 'task_repair_order') {
            if (!isset($where["task_repair_order.project_id"])) {
                $projectList = ProjectService::getInstance()->getUserProjectList($userId, ['param' => ['project_status' => 'inprogress']]);
                $projectIds = array_column(array_column($projectList['rows'], 'project'), 'id');
                if (!empty($projectIds)) {
                    $where["task_repair_order.project_id"] = ["IN", $projectIds];
                }
            }

            //默认的工序选中
            if (!isset($where["task_repair_order.step_id"]) && !empty($param['entity_module_code'])) {
                $stepCategoryList = StepService::getInstance()->getStepCategoryByMergeModuleConfig($param['entity_module_code'], false);
                $stepList = model(StepModel::class)->where(['step_category_id' => ['IN', array_column($stepCategoryList, 'id')]])->field('id')->select();
                if (!empty($stepList)) {
                    $where["task_repair_order.step_id"] = ['IN', array_column($stepList, 'id')];
                }
            }
        }

        $where[] = ['review_request.tenant_id' => auto_fill_tenant_id()];
        if (isset($isReviewed)) {
            if ($isReviewed == 1) {
                $where[] = ['review_request_node.is_reviewed' => "yes"];
            } else {
                $where[] = ['review_request_node.is_reviewed' => "no"];
                $where[] = ['review_request_node.is_active' => "yes"];
            }
        } else {
            $where[] = [
                ['review_request_node.is_reviewed' => "yes"],
                [
                    "review_request_node.is_reviewed" => "no",
                    "review_request_node.is_active" => "yes",
                ],
                "_logic" => "OR"
            ];
        }
        $realTableName = get_module_table_name($moduleData);

        //返修需要剧集筛选
        $needEpisodeFilterModule = ['task_repair_order'];

        $totalQuery = model(ReviewRequestModel::class)
            ->join("$realTableName AS {$moduleData['code']} on {$moduleData['code']}.id = review_request.link_id AND review_request.module_id={$moduleData['id']}")
            ->join("review_request_node  ON review_request.id = review_request_node.review_request_id");

        if (in_array($moduleData['code'], $needEpisodeFilterModule)) {
            $totalQuery = $totalQuery->join("entity on entity.id = {$moduleData['code']}.entity_id", "LEFT");
        }

        $total = $totalQuery->where($where)->count();
        $fields = array_merge($queryFields, $reviewRequestFields, $reviewRequestNodeFields);
        $fields = build_complex_query_fields($fields, '__');
        $query = model(ReviewRequestModel::class)
            ->join("$realTableName AS {$moduleData['code']} on {$moduleData['code']}.id = review_request.link_id AND review_request.module_id={$moduleData['id']}")
            ->join("review_request_node  ON review_request.id = review_request_node.review_request_id");


        if (in_array($moduleData['code'], $needEpisodeFilterModule)) {
            $query = $query->join("entity on entity.id = {$moduleData['code']}.entity_id", "LEFT");
        }

        $data = $query->where($where)->field($fields)->page(...$page)->order("review_request_node.is_reviewed DESC")->select();
        if (!empty($data)) {
            $extraData = null;
            if (!empty($moduleExtraQueryFields)) {
                $moduleExtraQueryFields = explode(',', $moduleExtraQueryFields);
                // 追加实体module_id查询
                $moduleExtraQueryFields[] = 'entity.module_id';
                $moduleExtraQueryFields[] = 'entity.entity_id';
                $moduleExtraQueryFields = array_unique($moduleExtraQueryFields);

                $modulePrimaryIdList = array_column($data, "{$moduleCode}__id");
                if ($moduleData['type'] === 'entity') {
                    $modelName = 'entity';
                } else {
                    $modelName = $moduleData['code'];
                }
                $commonService = CommonService::instance($modelName);
                $commonService->setCurrentModuleCode($moduleCode);
                $extraData = $commonService
                    ->select(['filter' => [
                        "{$moduleCode}.id" => ['IN', implode(',', $modulePrimaryIdList)]
                    ],
                        'fields' => implode(',', $moduleExtraQueryFields)
                    ], $moduleCode);
                if (!empty($extraData['rows'])) {
                    $extraData = $extraData['rows'];
                    $sequenceModuleId = Module::$moduleDictData['module_index_by_code']['sequence']['id'] ?? 0;
                    $shotModuleId = Module::$moduleDictData['module_index_by_code']['shot']['id'] ?? 0;
                    $sequenceEntityIdList = [];
                    $sequenceMap = [];
                    foreach ($extraData as &$extraDatum) {
                        $currentModuleId = $extraDatum['entity']['module_id'];
                        $currentModuleCode = Module::$moduleDictData['module_index_by_id'][$currentModuleId]['code'] ?? '';
                        if (isset($extraDatum['entity']['json'])) {
                            if (!empty($currentModuleCode)) {
                                foreach ($extraDatum['entity']['json'] as $jk => $jv) {
                                    $extraDatum['entity'][str_replace_once($currentModuleCode . '_', '', $jk)] = $jv;
                                }
                            } else {
                                $extraDatum['entity'] += $extraDatum['entity']['json'];
                            }
                            unset($extraDatum['entity']['json']);
                        }
                        if ($extraDatum['entity']['module_id'] === $sequenceModuleId) {
                            $extraDatum['sequence'] = $extraDatum['entity'];
                        } elseif ($extraDatum['entity']['module_id'] === $shotModuleId) {
                            $sequenceEntityIdList[$extraDatum['entity']['entity_id']] = $extraDatum['entity']['entity_id'];
                            $sequenceMap[$extraDatum['entity']['entity_id']] = null;
                            $extraDatum['shot'] = $extraDatum['entity'];
                            $extraDatum['sequence'] = &$sequenceMap[$extraDatum['entity']['entity_id']];

                        }
                        $extraDatum['primary_id'] = $extraDatum[$moduleCode]['id'];
                    }

                    // 查询序列信息
                    if (count($sequenceEntityIdList)) {
                        $sequenceList = model(EntityModel::class)->where(['id' => ['IN', $sequenceEntityIdList]])->field('id,name,code')->select();
                        $sequenceList = array_column($sequenceList, null, 'id');
                        foreach ($sequenceMap as $sequenceId => &$sequenceData) {
                            $sequenceData = $sequenceList[$sequenceId] ?? null;
                        }
                    }
                    $extraData = array_column($extraData, null, 'primary_id');
                }
            }
            $createdByUserIdList = array_column($data, 'review_request__created_by', 'review_request__created_by');
            $userMap = model(UserModel::class)->where(['id' => ['IN', $createdByUserIdList]])->field("json", true)->select();
            $userMap = array_column($userMap, null, 'id');
            foreach ($data as &$item) {
                $extraPrimaryId = $item["{$moduleCode}__id"];
                $item = separate_complex_query_data($item, '__');
                $item['created_by'] = $userMap[$item['review_request']['created_by']] ?? null;
                $extraItem = $extraData[$extraPrimaryId] ?? [];
                $item = array_merge($item, $extraItem);
            }
        }

        return ['total' => $total, 'rows' => $data];
    }

    /**
     * 拒绝反馈后的处理
     * @param array $reviewRequestNode
     * @param array $reviewRequest
     * @param int $taskId
     * @throws Exception
     * @throws Throwable
     */
    public function refuseReviewFeedback(array $reviewRequestNode, array $reviewRequest, int $taskId)
    {
        /**
         *
         * 拒绝反馈
         * 1. 更新任务审核状态为已提交
         * 1.1 判断任务是否是外包任务 外包任务 更新原始任务的审核状态
         * 2. 审核节点状态修改为已通过
         * 3. 检查是否还有下一步 没有下一步 结束审核 触发结束检查  有下一步激活下一步
         *
         */
        //下一步
        $requestReviewNodeModel = model(ReviewRequestNodeModel::class);
        $nextChild = $requestReviewNodeModel->where(['parent_id' => $reviewRequestNode['id']])->find();
        $taskWorkOrder = model(TaskWorkOrderModel::class)->where(['review_request_node_id' => $reviewRequestNode['id']])->field('id')->find();
        $taskUpdateFilter = ['id' => $taskId];
        $taskData = model(TaskModel::class)->find($taskId);
        $isPartyAReview = $reviewRequest['tenant_id'] !== $taskData['tenant_id'];

        if ($isPartyAReview) {
            $orderService = OrderService::getInstance();
            $taskData = $orderService->getSourceTaskByTaskId($taskId);
            if (empty($taskData)) {
                throw new LogicException("cant fount source task", ErrorCode::DATA_INVALID);
            }
            $taskUpdateFilter['id'] = $taskData['id'];
        }
        $playlistItemVersionList = model(PlaylistItemVersionModel::class)->where(['review_request_id' => $reviewRequest['id']])->field('id')->select();
        $playlistItemVersionIdList = [];
        $needNotifyNextNode = false;

        // 是否甲方环节制片提交过
        // 提交过进已提交 没提交过进待提交
        if (in_array($taskData['deal_status'], TaskModel::DEAL_STATUS_SUBMITTED_SCOPE)) {
            $taskUpdateData = [
                'deal_status' => 'submitted'
            ];
        } else {
            $taskUpdateData = [
                'deal_status' => 'no_submit'
            ];
        }

        //更新所有的检查点为通过
        $reviewRequestNodeSaveData = ['is_second_confirm' => 'yes', 'is_active' => 'no', 'is_pass' => 'yes', 'feedback_status' => 'reject_feedback'];
        if (!empty($reviewRequestNode['param'])) {
            $reviewRequestNodeParam = json_decode($reviewRequestNode['param'], true);
            foreach ($reviewRequestNodeParam as &$reviewRequestNodeParamItem) {
                $reviewRequestNodeParamItem['is_pass'] = 'yes';
            }
            $reviewRequestNodeSaveData['param'] = json_encode($reviewRequestNodeParam);
        }

        $requestReviewNodeModel->startTrans();
        try {
            //二次确认 以及审核确认
            model(ReviewRequestNodeModel::class)->where(['id' => $reviewRequestNode['id']])->save($reviewRequestNodeSaveData);
            model(TaskModel::class)->where($taskUpdateFilter)->save($taskUpdateData);
            if (!empty($playlistItemVersionList)) {
                $playlistItemVersionIdList = array_column($playlistItemVersionList, 'id');
            }

            if (!empty($nextChild)) {
                // 存在下一步 就激活下一步
                $nextChild = $requestReviewNodeModel->modifyItem([
                    'id' => $nextChild['id'],
                    'is_active' => 'yes',
                    'start_at' => time(),
                ]);
                $needNotifyNextNode = true;
                //通过则无需再进行二次确认,二次确认直接通过
                $playlistItemVersionIdTmp = ['current_review_code' => $nextChild['role_code'], 'deal_status' => 'submitted'];
            } else {
                //没有下一步 就更新审批状态 结束审批
                $this->requestReviewModel->modifyItem([
                    'id' => $reviewRequestNode['review_request_id'],
                    'is_pass' => "yes",
                    'is_reviewed' => "yes",
                    'reviewed' => time(),
                ]);
                $reviewRequest = model(ReviewRequestModel::class)->where(['id' => $reviewRequest['id']])->find();
                $playlistItemVersionIdTmp = ['deal_status' => 'processed', 'status' => 'review_done'];
            }

            //更新审核子项的状态
            if (!empty($playlistItemVersionIdList)) {
                model(PlaylistItemVersionModel::class)->where(['id' => ['IN', $playlistItemVersionIdList]])->save($playlistItemVersionIdTmp);
            }

            if (!empty($taskWorkOrder)) {
                TaskWorkOrderService::getInstance()->updateTaskWorkCreatedByUnread($taskWorkOrder['id'], "yes");
            }

            if (empty($nextChild)) {
                $this->afterReviewedFinished($reviewRequest);
            }

            $requestReviewNodeModel->commit();
            try {
                // 检查是否需要更新播放列表
                //由于外面加入了事务 ,双重
                Client::send('check_review_playlist_status', build_queue_data_with_xu(['id' => $reviewRequestNode['id']]), 10);
            } catch (Throwable $e) {
                trace(format_exception_info($e), 'ERR');
            }
        } catch (Throwable $e) {
            $requestReviewNodeModel->rollback();
            throw $e;
        }
        try {
            if ($needNotifyNextNode) {
                ReviewRequestMessageService::getInstance()->notifyReviewNextNode($nextChild);
            }
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 当审核节点审核完后
     * @param array $flag
     * @throws Exception
     * @throws Throwable
     */
    private function afterReviewRequestNodeReviewed(array $flag)
    {
        $nextChild = $this->requestReviewNodeModel->where(['parent_id' => $flag['id']])->find();
        $reviewRequest = model(ReviewRequestModel::class)->find($flag['review_request_id']);
        if ($flag['is_pass'] === 'yes') {
            //通过 无需再进行二次确认
            model(ReviewRequestNodeModel::class)->modifyItem(['id' => $flag['id'], 'is_second_confirm' => 'yes']);
            if (!empty($nextChild)) {
                $nextChildUpdate = model(ReviewRequestNodeModel::class)->modifyItem([
                    'id' => $nextChild['id'],
                    'is_active' => 'yes',
                    'start_at' => time(),
                ]);

                try {
                    ReviewRequestMessageService::getInstance()->notifyReviewNextNode($nextChild);
                } catch (Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
            } else {
                //没有下一步 就更新审批状态 结束审批
                $reviewRequest = $this->requestReviewModel->modifyItem(['id' => $flag['review_request_id'], 'is_pass' => "yes", 'is_reviewed' => "yes", 'reviewed' => time(),]);
            }
        } else {
            $isVersionReviewed = $reviewRequest['module_id'] === Module::$moduleDictData['module_index_by_code']['version']['id'];
            if ($isVersionReviewed) {
                // 审核不通过都需要进行审核反馈确认
                $noteListIds = model(NoteModel::class)->where(['review_request_node_id' => $flag['id']])->field('id')->column('id');
                if (!empty($noteListIds)) {
                    model(NoteModel::class)->where(['id' => ['IN', $noteListIds]])->save(['is_feedback_show' => 'yes']);
                }
            }

            // 结束当前审核
            $this->requestReviewModel->modifyItem(['id' => $flag['review_request_id'], 'is_reviewed' => "yes", 'is_pass' => "no", 'reviewed' => time(),]);
            // 二次确认状态更新
            model(ReviewRequestNodeModel::class)->modifyItem(['id' => $flag['id'], 'is_second_confirm' => 'yes']);

            // 剩下的审核节点
            $nextReviewRequestNodes = model(ReviewRequestNodeModel::class)->where(['review_request_id' => $reviewRequest['id']])->where(['id' => ['GT', $flag['id']]])->field('id')->select();
            if (count($nextReviewRequestNodes) > 0) {
                $nextReviewRequestNodeIdList = array_column($nextReviewRequestNodes, 'id');
                $this->requestReviewNodeModel->where(['id' => ['IN', $nextReviewRequestNodeIdList]])->save(['is_second_confirm' => 'yes', 'is_terminate' => 'yes']);
            }
            $reviewRequest = $this->requestReviewModel->where(['id' => $flag['review_request_id']])->find();
        }

        $reviewFinished = empty($nextChild) || $flag['is_pass'] === 'no';
        if ($reviewFinished) {
            $this->afterReviewedFinished($reviewRequest);
        }
    }

    /**
     * 外包任务甲方接收反馈
     * @param array $reviewRequest
     * @param array $reviewRequestNode
     * @param int $taskId
     * @throws \Exception
     */
    public function partyAReviewAcceptReviewNote(array $reviewRequest, array $reviewRequestNode, int $taskId)
    {
        /**
         * 外包审核接受反馈
         *      更新任务审核状态
         *      存储接受反馈的节点id
         *      更新订单任务列表的审核状态
         */

        $this->updateReviewNoPassStatus($reviewRequest);
        // 存储拒绝的节点id
        model(ReviewRequestModel::class)->execute("UPDATE review_request SET param = JSON_SET(IFNULL(param,'{}'),'$.review_deny_node_id',{$reviewRequestNode['id']}) where id = {$reviewRequest['id']}");
        $orderService = OrderService::getInstance();
        $orderTaskListItem = $orderService->getOrderTaskListItemByRealTaskId($taskId);
        model(OrderTaskListModel::class)->where(['id' => $orderTaskListItem['id']])->save(['deal_status' => 'pending']);

        // 制片接受，减少未处理数据记录
        Client::send('count_pending', build_queue_data_with_xu([
            'type' => 'review_submit_feedback',
            'mode' => 'sub',
            'data' => ["id" => $orderTaskListItem['task_id']]
        ]));
    }

    /**
     * 审核申请创建成功后
     * @param array $reviewRequest
     * @param array $reviewRequestNodes
     * @throws \Exception
     */
    private function afterReviewRequestCreated(array $reviewRequest, array $reviewRequestNodes)
    {
        $creator = UserService::getInstance()->getUserFindField(['id' => $reviewRequest['created_by']], '*');

        switch ($reviewRequest['module_id']) {
            case Module::$moduleDictData['module_index_by_code']['version']['id']:
                // 提交了一个版本的审核

                /**
                 * 添加审核人员到项目中
                 */
                $version = model(VersionModel::class)->find($reviewRequest['link_id']);
                if ($version['tenant_id'] === $reviewRequest['tenant_id']) {
                    // 内部审核
                    $projectService = ProjectService::getInstance();
                    $data = [
                        'user_list' => [],
                        'project_id' => $version['project_id'],
                    ];
                    foreach ($reviewRequestNodes as $node) {
                        $data['user_list'][] = [
                            'role_code' => $node['role_code'],
                            'user_id' => $node['plan_reviewer'],
                        ];
                    }

                    $projectService->batchCreateProjectMemberMultiRole($data);
//                    Client::send('batch_create_project_member_multi_role', json_encode($data));
                } else {
                    // 甲方审核乙方
                    $projectService = ProjectService::getInstance();
                    $orderService = OrderService::getInstance();
                    $sourceTask = $orderService->getSourceTaskByTaskId($version['link_id']);

                    if (empty($sourceTask)) {
                        throw new LogicException('partya already withdraw this task', ErrorCode::PARTYA_ALREADY_WITHDRAW_TASK);
                    }
                    $data = [
                        'user_list' => [],
                        'project_id' => $sourceTask['project_id'],
                    ];
                    foreach ($reviewRequestNodes as $node) {
                        $data['user_list'][] = [
                            'role_code' => $node['role_code'],
                            'user_id' => $node['plan_reviewer'],
                        ];
                    }

                    $projectService->batchCreateProjectMemberMultiRole($data);

                }


                break;
            case module_by_code('plan')['id']:
                $reviewRequestNode = $reviewRequestNodes[0];
                $params = [
                    'plan_id' => $reviewRequest['link_id'],
                    'confirm_end_time' => $reviewRequestNode['confirm_end_time']
                ];
                // 发送排期自动确认
                if ($reviewRequestNode['confirm_end_time'] > time()) {
                    Client::send("plan_confirm_end_time_auto_confirm", build_queue_data_with_xu($params), $reviewRequestNode['confirm_end_time'] - time());
                }
                $hookData = [
                    'type' => 'plan_review',
                    'data' => [
                        'review_request' => $reviewRequest,
                        'review_request_node' => $reviewRequestNode,
                        'creator' => $creator,
                    ],
                ];
                Hook::listen('review_request_created_after', $hookData);
                break;
            case module_by_code('task')['id']:
                $reviewRequestNode = $reviewRequestNodes[0];
                $hookData = [
                    'type' => 'task_delay_review',
                    'data' => [
                        'review_request' => $reviewRequest,
                        'review_request_node' => $reviewRequestNode,
                        'creator' => $creator,
                    ],
                ];
                Hook::listen('review_request_created_after', $hookData);
                break;
//            case module_by_code('delay_order_task')['id']:
//                //取到未审核且被激活的那一个
//                $reviewRequestNode = [];
//                foreach ($reviewRequestNodes as $reviewRequestNodesItem) {
//                    if (empty($reviewRequestNode) && $reviewRequestNodesItem['is_reviewed'] == 'no' && $reviewRequestNodesItem['is_active'] == 'yes') {
//                        $reviewRequestNode = $reviewRequestNodesItem;
//                    }
//                }
//                if (!empty($reviewRequestNode)) {
//                    $reviewManData = UserService::getInstance()->getUserFindField(['id' => $reviewRequestNode['plan_reviewer']], '*');
//                    $delayOrderName = model(DelayOrderModel::class)
//                        ->where(['id' => $reviewRequest['link_id']])
//                        ->value("name");
//                    if (!empty($delayOrderName)) {
//                        $messageParam = [
//                            'first' => '有新的延期单申请',
//                            'delay_order_name' => $delayOrderName,
//                            'sender_name' => $creator['name'],
//                            'remark' => '请及时审核',
//                            'delay_order_id' => $reviewRequest['link_id']
//                        ];
//                        $messageTemplateId = ReviewRequestMessageService::getInstance()->delayOrderConfirmMessageTemplateId();
//                        Client::send('send_notify_message_v2', build_queue_data_with_xu([
//                            "param" => $messageParam,
//                            'receiver' => $reviewManData['union_id'],
//                            'template_id' => $messageTemplateId,
//                            'content_type' => 'card_message',
//                            'notice_type' => 'examine',
//                            'is_popup' => 1,
//                            'message_key' => 'task_delay_order_need_review',
//                        ]));
//                    }
//                }
//                break;
        }
    }

    /**
     * 关闭审核申请
     * @param $reviewRequest
     * @return void
     * @throws \Exception
     */
    public function closeReviewRequest($reviewRequest)
    {
        model(ReviewRequestModel::class)->modifyItem(['id' => $reviewRequest['id'], 'is_pass' => 'no', 'is_reviewed' => 'yes', 'reviewed' => time(),]);
        $reviewRequestNodes = model(ReviewRequestNodeModel::class)->where(['review_request_id' => $reviewRequest['id']])->order('parent_id ASC')->select();
        $activeAfter = false;
        $reviewRequestNodeIdList = [];
        foreach ($reviewRequestNodes as $reviewRequestNode) {
            if ($reviewRequestNode['is_active'] === 'yes') {
                model(ReviewRequestNodeModel::class)->modifyItem(['id' => $reviewRequestNode['id'], 'is_pass' => 'no', 'is_reviewed' => 'yes', 'is_second_confirm' => 'yes', 'is_active' => 'no', 'reviewed' => time(),]);
                $activeAfter = true;
                continue;
            }
            if ($activeAfter) {
                $reviewRequestNodeIdList[] = $reviewRequestNode['id'];
            }
        }
        if (empty($reviewRequestNodeIdList)) {
            return;
        }
        model(ReviewRequestNodeModel::class)->where(['id' => ['IN', implode(',', $reviewRequestNodeIdList)]])->save(['is_pass' => 'no', 'is_reviewed' => 'yes', 'is_terminate' => 'yes', 'is_active' => 'no', 'is_second_confirm' => 'yes']);
    }

    /**
     * 查询审核进度
     * @param $reviewRequestIdList
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function queryReviewRequestProgressData($reviewRequestIdList)
    {
        $res = [];
        $notPassNodeIdList = [];
//        $executorUserId = [];
        $reviewRequestRoleCodeList = [];
        if (empty($reviewRequestIdList)) {
            return $res;
        }
        $reviewRequestList = model(ReviewRequestModel::class)->where(['id' => ['IN', implode(',', $reviewRequestIdList)]])->select();
        $reviewRequestCreatedByMap = array_column($reviewRequestList, null, 'id');
        $executorUserId = array_column($reviewRequestList, 'created_by', 'created_by');
        $res = model(ReviewRequestNodeModel::class)->where(['review_request_id' => ['IN', implode(',', $reviewRequestIdList)]])->select();
        if (empty($res)) {
            return $res;
        }

        $currentModuleCode = module_by_id($reviewRequestList[0]['module_id'])['code'];
        $res = array_group_by($res, 'review_request_id');
        foreach ($res as &$reviewRequestNodeList) {
            $reviewRequestNodeList = array_sort_by($reviewRequestNodeList, 'parent_id', 'ASC', false);
            foreach ($reviewRequestNodeList as &$reviewRequestNode) {
                $reviewRequestNode['review_not_pass'] = false;
                $reviewRequestRoleCodeList[$reviewRequestNode['role_code']] = $reviewRequestNode['role_code'];
                $executorUserId[$reviewRequestNode['plan_reviewer']] = $reviewRequestNode['plan_reviewer'];
                if ($reviewRequestNode['is_reviewed'] === 'yes' && $reviewRequestNode['is_pass'] === 'no') {
                    $notPassNodeIdList[] = $reviewRequestNode['id'];
                    $reviewRequestNode['review_not_pass'] = true;
                }
            }
        }
        unset($reviewRequestNodeList);
        $roleInfo = [];
        if (!empty($reviewRequestRoleCodeList)) {
            $roleInfoFilter = [
                'param' => [
                    'filter' => [
                        "role.code" => ['-in', join(",", $reviewRequestRoleCodeList)]
                    ]
                ],
                'fields' => "id,code,name"
            ];
            $roleInfo = teamones_request('teamones-im', 'role/select', $roleInfoFilter)['data']['rows'];
            $roleInfo = array_column($roleInfo, null, 'code');
        }
//        $userList = [];
//        if (!empty($executorUserId)) {
//            $userList = UserService::getInstance()->selectLocalUserList(['id' => ['IN', implode(',', $executorUserId)]]);
//            $userList = array_column($userList, null, 'id');
//        }
        // 未通过审核反馈查询
        $nodeNotPassNoteDict = [];
        if (!empty($notPassNodeIdList)) {
            $noteQueryFields = [
                'note.id',
                'note.type',
                'note.link_id',
                'note.module_id',
                'note.stick',
                'note.parent_id',
                'note.text',
                'note.last_updated',
                'note.created_by',
                'note.created',
                'note.json',
                'note.review_param',
                'note.review_request_node_id'
            ];
            $nodeNotPassNoteDict = model(NoteModel::class)
                ->where(['review_request_node_id' => ['IN', implode(',', $notPassNodeIdList)]])->field($noteQueryFields)->select();
            $nodeNotPassNoteDict = array_column($nodeNotPassNoteDict, null, 'review_request_node_id');
        }
        $createdByList = UserService::getInstance()->getUsersByUserIds($executorUserId);

        foreach ($createdByList as &$createdByItem) {
            $createdByItem['user_id'] = $createdByItem['saas_user']['id'];
        }
        $createdByList = array_column($createdByList, null, 'user_id');


        foreach ($res as $reviewRequestId => &$reviewRequestNodeList) {
            $reviewRequest = $reviewRequestCreatedByMap[$reviewRequestId] ?? null;
            $firstNode = [
                'role' => null,
                'plan_reviewer_user' => null,
                'reviewed' => null
            ];
            if (isset($createdByList[$reviewRequest['created_by']])) {
                $firstNode = [
                    'role' => $createdByList[$reviewRequest['created_by']]['role'],
                    'plan_reviewer_user' => $createdByList[$reviewRequest['created_by']]['saas_user'],
                    'reviewed' => $reviewRequest['created']
                ];
            }
            foreach ($reviewRequestNodeList as &$node) {
                $node['role'] = $roleInfo[$node['role_code']] ?? null;
                $node['plan_reviewer_user'] = $createdByList[$node['plan_reviewer']]['saas_user'] ?? null;
                $node['note'] = null;
                if ($node['review_not_pass']) {
                    $node['note'] = $nodeNotPassNoteDict[$node['id']] ?? null;
                }
            }
            array_unshift($reviewRequestNodeList, $firstNode);
        }
        return $res;
    }

    /**
     * 查询审核进度-v2
     * @param $reviewRequestId
     * @return array|array[]|false|mixed|string
     * @throws \Exception
     */
    public function queryReviewRequestProgressList($reviewRequestId)
    {
        if (empty($reviewRequestId)) {
            return [];
        }
        $reviewRequestList = model(ReviewRequestModel::class)->where(['id' => $reviewRequestId])->find();
        $res = model(ReviewRequestNodeModel::class)
            ->field('id,review_request_id,is_pass,is_reviewed,is_active,reviewed,parent_id,plan_reviewer,role_code')
            ->where(['review_request_id' => $reviewRequestId])
            ->order('parent_id ASC')
            ->select();
        if (empty($res)) {
            return [];
        }
        $createdByList = UserService::getInstance()->getUsersByUserIds([$reviewRequestList['created_by']]);
        foreach ($createdByList as &$createdByItem) {
            $createdByItem['user_id'] = $createdByItem['saas_user']['id'];
        }
        $createdByList = array_column($createdByList, null, 'user_id');
        if (!empty($reviewRequestList)) {
            $firstNode = [
                'id' => 0,
                'plan_reviewer' => 0,
                'reviewed' => 0,
                'review_request_id' => 0,
                'is_pass' => 'yes',
                'is_reviewed' => 'yes',
                'is_active' => 'no',
                'role_code' => null
            ];
            if (isset($reviewRequestList['created_by'])) {
                $firstNode = [
                    'id' => 0,
                    'plan_reviewer' => $reviewRequestList['created_by'],
                    'reviewed' => $reviewRequestList['created'],
                    'review_request_id' => $reviewRequestId,
                    'is_pass' => 'yes',
                    'is_reviewed' => 'yes',
                    'is_active' => 'no',
                    'role_code' => $createdByList[$reviewRequestList['created_by']]['role']['code'] ?? null
                ];
            }
            $res = array_merge([$firstNode], $res);
        }
        return $res;
    }

    /**
     * 批量创建审核反馈
     * @throws \Exception|\Throwable
     */
    public function batchCreate($data, $createdBy)
    {
        //获取审核处理数据
        list($reviewRequestUUId, $reviewRequestDataMap, $nodesDataMap, $isPassAllIndexList) = $this->dealBatchReviewRequestData($data, $createdBy);

        $this->requestReviewModel->startTrans();
        try {
            //批量插入审核数据

            $reviewRequest = $this->requestReviewModel->addAll(array_values($reviewRequestDataMap));
            if (!$reviewRequest) {
                throw new LogicException($this->requestReviewModel->getError(), ErrorCode::REVIEW_ADD_FAILURE);
            }

            //拿到批量插入之后的id
            $reviewRequestIds = $this->requestReviewModel->where(['uuid' => ["IN", $reviewRequestUUId]])->field("id,uuid")->select();
            $reviewRequestMap = array_column($reviewRequestIds, 'id', 'uuid');

            $reviewRequestIndexToIdMap = [];
            $isPassReviewRequestList = [];
            foreach ($reviewRequestDataMap as $reviewRequestDataMapIndex => $reviewRequestDataMapItem) {
                $reviewRequestIndexToIdMap[$reviewRequestDataMapIndex] = $reviewRequestDataMapItem['id'] = $reviewRequestMap[$reviewRequestDataMapItem['uuid']];
                $reviewRequestDataMap[$reviewRequestDataMapIndex] = $reviewRequestDataMapItem;
                if (isset($isPassAllIndexList[$reviewRequestDataMapIndex])) {
                    $isPassReviewRequestList[] = $reviewRequestDataMapItem;
                }
            }

            //批量创建审核反馈节点
            $nodesDataGroup = $this->afterBatchReviewRequestNodeData($nodesDataMap, $reviewRequestIndexToIdMap);

            //审核申请批量创建成功后
            $this->afterReviewRequestBatchCreated($reviewRequestDataMap, $createdBy, $nodesDataGroup);

            //审核申请批量批量
            $this->afterReviewedBatchFinished($isPassReviewRequestList, $nodesDataGroup);
            $this->requestReviewModel->commit();

            //返回数据处理
            $res = [];
            foreach ($reviewRequestDataMap as $reviewRequestDataMapItem) {
                if (!empty($reviewRequestDataMapItem['param'])) {
                    $reviewRequestDataMapItem['param'] = json_decode($reviewRequestDataMapItem['param'], true);
                }
                $res[] = [
                    'review_request' => $reviewRequestDataMapItem,
                    'nodes' => $nodesDataGroup[$reviewRequestDataMapItem['id']]
                ];
            }
            return $res;
        } catch (Throwable $e) {
            $this->requestReviewModel->rollback();
            throw $e;
        }
    }

    /**
     * 处理批量审核数据
     * @param $data
     * @param $createdBy
     * @return array
     * @throws \Exception
     */
    private function dealBatchReviewRequestData($data, $createdBy)
    {
        $reviewRequestUUId = [];
        $reviewRequestDataMap = [];
        $nodesDataMap = [];
        $isPassAllIndexList = [];

        $delayTaskIds = [];
        foreach ($data as $dataIndex => $dataItem) {
            $reviewersData = $dataItem['reviewers'];
            $reviewRequestData = $dataItem['data'];
            $nodesData = [];
            $reviewerActivated = false;
            // 校验是否申请过延期
            if (!empty($reviewRequestData['link_id'])
                && !empty($reviewRequestData['param']['task_delay_time'])
                && !empty($reviewRequestData['module_id'])
                && $reviewRequestData['module_id'] == module_by_code('task')['id']
            ) {
                $delayTaskIds[] = $reviewRequestData['link_id'];
            }

            $isPassAll = true;
            foreach ($reviewersData as $key => $reviewer) {
                $skip = $reviewer['skip'];
                // 第一个节点并且没有跳过的节点
                // 不需要跳过得第一个节点 必须要激活
                $isActive = "no";
                if ($key == 0 && !$skip || !$skip && !$reviewerActivated) {
                    $reviewerActivated = true;
                    $isActive = "yes";
                }
                // 是否全部跳过判断标识
                if (!$skip) {
                    $isPassAll = false;
                }
                $tmp = [
                    'role_code' => $reviewer['role_code'],
                    'plan_reviewer' => $reviewer['user_id'],
                    'real_reviewer' => $skip ? $reviewer['user_id'] : 0,
                    'is_pass' => $skip ? "yes" : "no", //是否通过  跳过的直接自动通过
                    'is_reviewed' => $skip ? "yes" : "no", //默认都没有审核
                    'is_active' => $isActive, //激活状态
                    'start_at' => $isActive === 'yes' ? time() : 0,
                    'reviewed' => $skip ? time() : 0,
                    'is_second_confirm' => $skip ? 'yes' : 'no'
                ];
                if (!empty($reviewer['param'])) {
                    $tmp['param'] = json_encode($reviewer['param']);
                }
                if (isset($reviewer['confirm_end_time'])) {
                    $tmp['confirm_end_time'] = $reviewer['confirm_end_time'];
                }
                $nodesData[] = $tmp;
            }
            //当前所有节点都跳过就直接通过审批
            if ($isPassAll) {
                $reviewRequestData['is_reviewed'] = "yes";
                $reviewRequestData['reviewed'] = time();

                $isPassAllIndexList[$dataIndex] = true;
            }

            if (!empty($reviewRequestData['param'])) {
                $reviewRequestData['param'] = json_encode($reviewRequestData['param']);
            }

            $reviewRequestData['is_pass'] = $isPassAll ? "yes" : "no";
            $reviewRequestData['created'] = time();
            $reviewRequestData['created_by'] = $createdBy;
            $reviewRequestData['uuid'] = create_uuid();
            $reviewRequestData['tenant_id'] = auto_fill_tenant_id();
            $reviewRequestUUId[] = $reviewRequestData['uuid'];
            $reviewRequestDataMap[$dataIndex] = $reviewRequestData;
            $nodesDataMap[$dataIndex] = $nodesData;
        }

        // 校验是否申请过延期
        if (!empty($delayTaskIds)) {
            $this->checkBatchDelay($delayTaskIds);
        }

        return [
            $reviewRequestUUId, $reviewRequestDataMap, $nodesDataMap, $isPassAllIndexList
        ];
    }

    /**
     * 批量创建审核节点数据
     * @throws \Exception
     */
    public function afterBatchReviewRequestNodeData($nodesDataMap, $reviewRequestIndexLinkIdMap)
    {
        $nodeParentIdMap = [];
        $nodesDataList = [];

        $nodesUUIds = [];
        foreach ($nodesDataMap as $nodesDataIndex => $nodesData) {
            foreach ($nodesData as $nodesIndex => $nodesItem) {
                $nodesItem['review_request_id'] = $reviewRequestIndexLinkIdMap[$nodesDataIndex];
                $nodesItem['uuid'] = create_uuid();
                $nodesDataList[] = $nodesItem;
                if (isset($nodesData[$nodesIndex + 1])) {
                    $nodeParentIdMap[$nodesDataIndex][$nodesIndex + 1] = ['parent_uuid' => $nodesItem['uuid']];
                }
                if (isset($nodeParentIdMap[$nodesDataIndex][$nodesIndex])) {
                    $nodeParentIdMap[$nodesDataIndex][$nodesIndex]['current_uuid'] = $nodesItem['uuid'];
                }

                $nodesUUIds[] = $nodesItem['uuid'];
            }
        }

        //批量添加审核节点
        $node = $this->requestReviewNodeModel->addAll($nodesDataList);
        $requestReviewNodeList = $this->requestReviewNodeModel->where(['uuid' => ["IN", $nodesUUIds]])->field("id,uuid")->select();
        $requestReviewNodeMap = array_column($requestReviewNodeList, 'id', 'uuid');

        if (!$node) {
            throw new LogicException($this->requestReviewNodeModel->getError(), ErrorCode::REVIEW_ADD_FAILURE);
        }

        //批量更新parent_id
        $updateNodeParentIdMap = [];
        if (!empty($nodeParentIdMap)) {
            $updateNodeData = [];
            foreach ($nodeParentIdMap as $nodeParentIdMapData) {
                foreach ($nodeParentIdMapData as $nodeParentIdMapDataItem) {
                    $updateNodeData[] = [
                        'id' => $requestReviewNodeMap[$nodeParentIdMapDataItem['current_uuid']],
                        'parent_id' => $requestReviewNodeMap[$nodeParentIdMapDataItem['parent_uuid']]
                    ];
                    $updateNodeParentIdMap[$nodeParentIdMapDataItem['current_uuid']] = $requestReviewNodeMap[$nodeParentIdMapDataItem['parent_uuid']];
                }
            }
            //批量更新
            $this->requestReviewNodeModel->saveAll($updateNodeData);
        }

        //补齐数据
        $nodesDataGroup = [];
        foreach ($nodesDataList as $nodesDataItem) {
            $nodesDataItem['id'] = $requestReviewNodeMap[$nodesDataItem['uuid']];
            $nodesDataItem['parent_id'] = $updateNodeParentIdMap[$nodesDataItem['uuid']] ?? 0;
            $nodesDataGroup[$nodesDataItem['review_request_id']][] = $nodesDataItem;
        }

        return $nodesDataGroup;
    }

    /**
     * 审核申请批量创建成功后
     * @param array $reviewRequest
     * @param $createdBy
     * @param array $reviewRequestNodesGroup
     */
    private function afterReviewRequestBatchCreated(array $reviewRequest, $createdBy, array $reviewRequestNodesGroup)
    {
        $creator = UserService::getInstance()->getUserFindField(['id' => $createdBy], '*');

        $module = module_by_id($reviewRequest[0]['module_id']);
        switch ($module['code']) {
            case 'task':
                $taskIds = [];
                $taskReviewRequestMap = [];
                $planReviewerList = [];
                foreach ($reviewRequest as $reviewRequestItem) {
                    $reviewRequestNode = $reviewRequestNodesGroup[$reviewRequestItem['id']][0];
                    $taskIds[] = $reviewRequestItem['link_id'];
                    $reviewRequestItem['review_request_node'] = $reviewRequestNode;
                    $taskReviewRequestMap[$reviewRequestItem['link_id']] = $reviewRequestItem;
                    $planReviewerList[$reviewRequestNode['plan_reviewer']] = $reviewRequestNode['plan_reviewer'];
                }
                $planReviewerList = array_values($planReviewerList);

                $reviewManData = UserService::getInstance()->selectLocalUserList(['id' => ["IN", $planReviewerList]], ['id', 'union_id']);
                $reviewManData = array_column($reviewManData, 'union_id', 'id');

                $fields = [
                    'entity.initial_episode_code', 'entity.showings_number', 'entity.name', 'entity.module_id',
                    'task.name', 'task.id'
                ];
                $taskEntityList = model(EntityModel::class)
                    ->join('task on task.entity_id = entity.id')
                    ->where(['task.id' => ['IN', $taskIds]])
                    ->field(build_complex_query_fields($fields, '__'))
                    ->select();

                if (!empty($taskEntityList)) {
                    $messageTemplateId = ReviewRequestMessageService::getInstance()->taskDelayConfirmMessageTemplateId();

                    $sendMessageData = [];
                    foreach ($taskEntityList as $taskEntity) {
                        $hookData = [
                            'type' => 'task_delay_review_batch',
                            'data' => [
                                'task_entity' => separate_complex_query_data($taskEntity, '__'),
                                'message_template_id' => $messageTemplateId,
                                'review_man_data' => $reviewManData,
                                'review_request' => $taskReviewRequestMap[$taskEntity['task']['id']],
                                'creator' => $creator,
                            ],
                        ];
                        Hook::listen('review_request_created_after', $hookData);
                    }

                    //批量发送消息

                    foreach ($sendMessageData as $sendMessageDataItem) {
                        Client::send('send_notify_message_v2', build_queue_data_with_xu($sendMessageDataItem));
                    }
                }
                break;
        }
    }

    /**
     * 审核之后批量完成
     * @throws \Throwable
     */
    private function afterReviewedBatchFinished($reviewRequestList, $reviewRequestNodesGroup)
    {
        if (empty($reviewRequestList)) {
            return;
        }

        $module = module_by_code($reviewRequestList[0]['module_id']);

        $latestReviewedRequestReviewNodeMap = [];

        $latestPlanReviewer = [];
        foreach ($reviewRequestList as $reviewRequestItem) {
            $latestReviewedRequestReviewNode = array_pop($reviewRequestNodesGroup[$reviewRequestItem['id']]);
            $latestReviewedRequestReviewNodeMap[$reviewRequestItem['id']] = $latestReviewedRequestReviewNode;
            $latestPlanReviewer[$latestReviewedRequestReviewNode['plan_reviewer']] = $latestReviewedRequestReviewNode['plan_reviewer'];
        }

        $latestPlanReviewer = array_values($latestPlanReviewer);

        $latestReviewedRequestReviewer = UserService::getInstance()->selectLocalUserList(['id' => ["IN", $latestPlanReviewer]], '*');
        $latestReviewedRequestReviewer = array_column($latestReviewedRequestReviewer, null, 'id');
        //todo 暂时只写了延期类型的
        switch ($module['code']) {
            case 'task':
                // 任务延期

                $taskIds = [];
                $reviewRequestMap = [];
                $requestReviewCreatedBy = [];
                foreach ($reviewRequestList as $reviewRequestItem) {
                    $taskIds[$reviewRequestItem['link_id']] = $reviewRequestItem['link_id'];
                    $reviewRequestMap[$reviewRequestItem['link_id']] = $reviewRequestItem;
                    $requestReviewCreatedBy[$reviewRequestItem['created_by']] = $reviewRequestItem['created_by'];
                }
                $requestReviewCreatedBy = array_values($requestReviewCreatedBy);

                $taskIds = array_values($taskIds);

                $fields = [
                    'entity.initial_episode_code', 'entity.showings_number', 'entity.name', 'entity.module_id',
                    'task.name',
                ];
                $taskEntityList = model(EntityModel::class)
                    ->join('task on task.entity_id = entity.id')
                    ->where(['task.id' => ["IN", $taskIds]])
                    ->field(build_complex_query_fields($fields, '__'))
                    ->select();
                if (!empty($taskEntityList)) {
                    $messageDataList = [];
                    $messageTemplateId = ReviewRequestMessageService::getInstance()->taskDelayResultMessageTemplateId();
                    $creator = UserService::getInstance()->getUserFindField(['id' => ["IN", $requestReviewCreatedBy]], '*');
                    $creator = array_column($creator, null, 'id');
                    foreach ($taskEntityList as $taskEntity) {
                        $requestReview = $reviewRequestMap[$taskEntity['task']['id']];
                        $hookData = [
                            'type' => 'task_delay_review_result_batch',
                            'data' => [
                                'task_entity' => separate_complex_query_data($taskEntity, '__'),
                                'message_template_id' => $messageTemplateId,
                                'review_request' => $requestReview,
                                'review_request_node' => $latestReviewedRequestReviewNodeMap[$requestReview['id']],
                                'reviewer' => $latestReviewedRequestReviewer[$latestReviewedRequestReviewNodeMap[$requestReview['id']]['reviewed']],
                                'creator' => $creator,
                            ],
                        ];
                        Hook::listen('review_request_finished_after', $hookData);
                    }
                }


                break;
        }
    }


    /**
     * 校验是否申请过延期
     * @param $taskIds
     * @return array
     */
    public function checkBatchDelay($taskIds)
    {
        if (empty($taskIds)) {
            return [];
        }
        $taskDelay = model(ReviewRequestModel::class)
            ->where(['module_id' => module_by_code('task')['id'], 'link_id' => ["IN", $taskIds], 'is_pass' => 'no', 'is_reviewed' => 'no'])
            ->field('link_id,module_id,is_pass,name,param')
            ->find();
        if (!empty($taskDelay)) {
            throw new LogicException('delay already apply', ErrorCode::DELAY_ALREADY_APPLY);
        }
    }

    /**
     * 延期申请任务修改时间
     * @param $data
     * @return void
     * @throws \Throwable
     */
    public function delayRequestTaskUpdateDelayTime($data)
    {
        if (isset($data['id']) && isset($data['plan_end_time'])) {
            $taskId = $data['id'];
            $planModel = model(PlanModel::class);
            $plan = $planModel->where(['task_id' => $taskId])->field("id")->find();
            $planData = [];
            if (!empty($plan)) {
                $planData = [
                    'id' => $plan['id'],
                    'end_time' => $data['plan_end_time']
                ];

                if (isset($data['plan_start_time'])) {
                    $planData['start_time'] = $data['plan_start_time'];
                }
            }

            $planModel->startTrans();
            try {
                if (!empty($planData)) {
                    $planModel->modifyItem($planData);
                }
                model(TaskModel::class)->modifyItem($data);
                $planModel->commit();
            } catch (Throwable $e) {
                $planModel->rollback();
                throw $e;
            }
        }
    }


    /**
     * 延期单延期时间更新
     * @param $delayOrder
     * @return void
     * @throws \Throwable
     * @throws \think\Exception
     */
    public function delayRequestDelayOrderUpdateDelayTime($delayOrder)
    {
        //拿取到任务中最大的时间
        $delayOrderTaskList = model(DelayOrderTaskModel::class)->where(['delay_order_id' => $delayOrder['id']])->select();

        //比较最大时间是否超出计划的时间,否则就需要更改计划的时间
        $maxTime = 0;
        $updateTaskData = [];
        $taskIds = [];
        foreach ($delayOrderTaskList as $delayOrderTaskItem) {
            $maxTime = max($maxTime, $delayOrderTaskItem['delay_time']);
            $taskIds[] = $delayOrderTaskItem['task_id'];
        }

        $taskList = model(TaskModel::class)->where(['id' => ["IN", $taskIds]])->field("id,JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_delay_sum')) as task_delay_sum")->select();
        $taskDelaySumMap = array_column($taskList, 'task_delay_sum', 'id');

        foreach ($delayOrderTaskList as $delayOrderTaskItem) {
            $updateTaskTmp = [
                'id' => $delayOrderTaskItem['task_id'],
                'plan_end_time' => date("Y-m-d H:i:s", $delayOrderTaskItem['delay_time']),
                'task_delay_sum' => ($taskDelaySumMap[$delayOrderTaskItem['task_id']] ?? 0) + 1,
            ];

            //如果超过了交付时间要更改交付时间
            if ($delayOrderTaskItem['delay_time'] > $updateTaskTmp['plan_delivery_time']) {
                $updateTaskTmp['plan_delivery_time'] = $delayOrderTaskItem['delay_time'];
            }
            $updateTaskData[] = $updateTaskTmp;
        }

        $planModel = model(PlanModel::class);
        $plan = $planModel
            ->join("task_relation_tag s_tag on s_tag.task_id = plan.task_id and s_tag.link_module_code in ('step_category','show_step_category')")
            ->where([
                'plan.project_id' => $delayOrder['project_id'],
                'plan.type' => PlanModel::TYPE_STEP_CATEGORY,
                'plan.scope' => PlanModel::SCOPE_SINGLE,
                'plan.entity_id' => $delayOrder['episode_id'],
                's_tag.link_id' => $delayOrder['step_category_id'],
            ])
            ->field("s_tag.link_id as step_category_id,plan.id,plan.entity_id,plan.end_time")
            ->find();


        //批量更新任务时间 ,延期次数增加
        $planModel->startTrans();
        try {
            if (!empty($updateTaskData)) {
                CommonService::instance("task")->commonBatchUpdate($updateTaskData, module_by_code('task'), false);
            }
            if (!empty($plan['end_time']) && $maxTime > $plan['end_time']) {
                $planModel->modifyItem(['id' => $plan['id'], 'end_time' => date("Y-m-d H:i:s", $maxTime)]);
            }
            $planModel->commit();
        } catch (\Throwable $e) {
            $planModel->rollback();
            throw $e;
        }
    }

    /**
     * 处理审核意见数据
     * @param $reviewRequest
     * @param $node
     * @param $data
     * @param $noteItem
     * @return array
     */
    public function dealReviewNoteData($reviewRequest, $node, &$data, &$noteItem)
    {
        $reviewModuleCode = module_by_id($reviewRequest['module_id'])['code'];
        switch ($reviewModuleCode) {
            case 'version':
                $version = model(VersionModel::class)->field('id,link_id,module_id')->find($reviewRequest['link_id']);
                if (empty($data['param']) && !empty($version)) {
                    $versionCheckListList = model(VersionCheckListModel::class)->where(['version_id' => $version['id']])->select();
                    $data['param'] = [];
                    foreach ($versionCheckListList as $versionChecklist) {
                        $data['param'][] = [
                            "is_pass" => $data['is_pass'],
                            'is_reviewed' => 'yes',
                            'check_list_id' => $versionChecklist['check_list_id'],
                            'version_check_list_id' => $versionChecklist['id'],
                        ];
                    }
                }
                if (!empty($noteItem)) {
                    $noteLinkId = $noteItem["note"]["link_id"];
                    $noteTask = model(TaskModel::class)
                        ->join("entity on entity.id = task.entity_id")
                        ->join("module on module.id = entity.module_id")
                        ->where(["task.id" => $noteLinkId])
                        ->field(["task.id", "task.entity_id", "task.project_id",
                            "entity.initial_episode_code", "module.code as module_code",
                            "JSON_UNQUOTE(JSON_EXTRACT(entity.json, CONCAT('$.',module.code,'_design'))) as design",
                            "JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.shot_storyboard')) as shot_storyboard",
                        ])
                        ->find();

                    $noteEntityRelation = [
                        "relation_type" => "step",
                        "relate_module_code" => in_array($noteTask["module_code"], ["asset", "level", "design"]) ? "asset" : "shot",
                        "project_id" => $noteTask["project_id"],
                        "episode_code" => $noteTask["initial_episode_code"],
                        "entity_id" => $noteTask["entity_id"],
                        "task_id" => $noteTask["id"],
                        "version_id" => $noteItem["note"]["version_id"],
                        'review_request_id' => $node['review_request_id'],
                        'review_request_node_id' => $node['id'],
                    ];

                    $noteItem["note"]["demand_type"] = "review_feedback";
                    $noteItem["note"]["review_request_node_id"] = $node["id"];
                    $noteItem["note"]["role_code"] = $node["role_code"];
                    $noteItem["note"]["module_id"] = module_by_code("task")["id"];
                    $noteItem['note']['module_code'] = $noteEntityRelation["relate_module_code"];
                    $noteItem['note']['project_id'] = $noteEntityRelation["project_id"];
                    $noteItem["note_entity_relation"] = [$noteEntityRelation];
                }

                break;
            case 'delay_order_task':
                $noteItem["note"]["review_request_node_id"] = $node["id"];
                $noteItem["note"]["role_code"] = $node["role_code"];
                $noteItem["note"]["module_id"] = module_by_code("delay_order_task")["id"];
                $noteItem["note"]['link_id'] = $reviewRequest['link_id'];
                break;
        }

        return $noteItem;
    }


    /**
     * 延期单任务延期时间更新
     * @param $delayOrderTask
     * @return void
     * @throws \think\Exception
     */
    public function delayRequestDelayOrderTaskUpdateDelayTime($delayOrderTask)
    {
        //比较最大时间是否超出计划的时间,否则就需要更改计划的时间
        $taskId = $delayOrderTask['task_id'];
        $task = model(TaskModel::class)->field("id,JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_delay_sum')) as task_delay_sum")->find($taskId);

        $updateTaskTmp = [
            'id' => $taskId,
            'plan_end_time' => date("Y-m-d H:i:s", $delayOrderTask['delay_time']),
            'task_delay_sum' => ($task['task_delay_sum'] ?? 0) + 1,
        ];

        //如果超过了交付时间要更改交付时间
        if ($delayOrderTask['delay_time'] > $delayOrderTask['plan_delivery_time']) {
            $updateTaskTmp['plan_delivery_time'] = $delayOrderTask['delay_time'];
        }
        //更改任务时间
        if (!empty($updateTaskTmp)) {
            CommonService::instance("task")->commonUpdate(["data" => $updateTaskTmp], module_by_code('task'), false);
        }
    }


    /**
     * 延期任务审核处理
     * @param $requestReview
     * @param $latestReviewedRequestReviewNode
     * @return void
     * @throws \Throwable
     */
    public function delayOrderTaskReview($requestReview, $latestReviewedRequestReviewNode)
    {
        //加锁
        $delayOrderTask = model(DelayOrderTaskModel::class)->find($requestReview['link_id']);

        if (empty($delayOrderTask)) {
            return;
        }

        $delayOrderTaskId = $delayOrderTask['id'];
        $mutex = new PHPRedisMutex([Redis::connection()->client()], "delay_order_task_review-$delayOrderTaskId");
        $mutex->synchronized(function () use ($requestReview, $latestReviewedRequestReviewNode, $delayOrderTask) {
            //如果没有下一个人或者都审核不通过了,则通知最终结果给提交人
            $delayOrder = model(DelayOrderModel::class)
                ->join("user on user.id = delay_order.created_by")
                ->where(['delay_order.id' => $delayOrderTask['delay_order_id']])
                ->field("delay_order.*,user.name as created_by_name")
                ->find();
            if ($requestReview['is_pass'] == 'yes') {
                $this->delayRequestDelayOrderTaskUpdateDelayTime($delayOrderTask);
            }

            //判定该时期其他的延期任务是否被审核过了
            $fields = [
                'delay_order_task.id',
                'review_request.id',
                'review_request.is_reviewed',
                'review_request.is_pass',
                'review_request_node.is_pass',
                'review_request_node.is_reviewed',
                'review_request_node.plan_reviewer',
                'review_request_node.role_code',
                'review_request_node.is_terminate',
                'review_request_node.parent_id',
            ];
            $reviewRequestList = model(DelayOrderTaskModel::class)
                ->join("review_request on review_request.link_id = delay_order_task.id and review_request.module_id=" . module_by_code("delay_order_task")['id'])
                ->join("review_request_node on review_request_node.review_request_id = review_request.id")
                ->where([
                    'delay_order_id' => $delayOrderTask['delay_order_id']
                ])
                ->field(build_complex_query_fields($fields, '__'))
                ->select();

            $noPassReviewRequestIds = [];
            $isReviewDelayOrderTaskCount = 0;
            $reviewer = [];
            $delayOrderTaskIds = [];
            $currentBeforeNoPassReviewRequestIds = [];
            $nextReviewer = 0;
            foreach ($reviewRequestList as $reviewRequestItem) {
                $reviewRequestItem = separate_complex_query_data($reviewRequestItem, '__');
                $reviewer[$reviewRequestItem['review_request_node']['plan_reviewer']] = $reviewRequestItem['review_request_node']['plan_reviewer'];
                $delayOrderTaskIds[$reviewRequestItem['delay_order_task']['id']] = $reviewRequestItem['delay_order_task']['id'];

                if ($reviewRequestItem['review_request']['is_reviewed'] == 'yes' && $reviewRequestItem['review_request']['is_pass'] == 'no') {
                    $noPassReviewRequestIds[$reviewRequestItem['review_request']['id']] = $reviewRequestItem['review_request']['id'];
                }

                if ($latestReviewedRequestReviewNode['id'] == $reviewRequestItem['review_request_node']["parent_id"]) {
                    $nextReviewer = $reviewRequestItem['review_request_node']['plan_reviewer'];
                }

                //当前角色,当前审核人
                if ($latestReviewedRequestReviewNode['plan_reviewer'] == $reviewRequestItem['review_request_node']['plan_reviewer'] &&
                    $latestReviewedRequestReviewNode['role_code'] == $reviewRequestItem['review_request_node']['role_code']
                ) {
                    //当前这一批延期任务的申请情况
                    //判定是否被中断了
                    if ($reviewRequestItem['review_request_node']['is_terminate'] == "no" &&
                        $reviewRequestItem['review_request_node']['is_reviewed'] == 'yes') {
                        ++$isReviewDelayOrderTaskCount;
                    }
                } elseif ($latestReviewedRequestReviewNode['is_reviewed'] == "yes") { //不是当前这一批且审核过的
                    if ($latestReviewedRequestReviewNode['is_pass'] == "no") {
                        $currentBeforeNoPassReviewRequestIds[$reviewRequestItem['review_request']['id']] = $reviewRequestItem['review_request']['id'];
                    }
                }
            }

            $delayOrderTaskCount = count($delayOrderTaskIds);
            $noPassReviewRequestCount = count($noPassReviewRequestIds);
            //非失败数
            $noFailCount = $delayOrderTaskCount - $noPassReviewRequestCount;
            $userNames = model(UserModel::class)->where(['id' => ["IN", array_values($reviewer)]])->column('name');

            //是否都不通过
            if (empty($noFailCount)) {
                $hookData = [
                    'type' => 'delay_order_result',
                    'data' => [
                        'is_pass' => false,
                        'review_names' => $userNames,
                        'reviewed' => $latestReviewedRequestReviewNode['reviewed'],
                        'delay_order' => $delayOrder,
                    ],
                ];
                Hook::listen('delay_order_created_after', $hookData);
                model(DelayOrderModel::class)->modifyItem(['id' => $delayOrder['id'], 'is_reviewed' => 'yes']);
            } else {
                // 当前审核数是否等于剩余通过数
                $isAllReview = $isReviewDelayOrderTaskCount == ($delayOrderTaskCount - count($currentBeforeNoPassReviewRequestIds));
                //是否都审核完了
                if ($isAllReview) {
                    //判定是否还存在下一个人,则通知下一个人 , 否则拿到最后的结果去通知提交人
                    if (!empty($nextReviewer)) {
                        $hookData = [
                            'type' => 'delay_order_confirm',
                            'data' => [
                                'delay_order' => $delayOrder,
                                'creator_name' => $delayOrder['created_by_name'],
                                'step_category_id' => $nextReviewer,
                            ],
                        ];
                        Hook::listen('delay_order_created_after', $hookData);
                    } else {
                        $hookData = [
                            'type' => 'delay_order_result',
                            'data' => [
                                'is_pass' => $noPassReviewRequestCount == 0,
                                'review_names' => $userNames,
                                'reviewed' => $latestReviewedRequestReviewNode['reviewed'],
                                'delay_order' => $delayOrder,
                            ],
                        ];
                        Hook::listen('delay_order_created_after', $hookData);
                        model(DelayOrderModel::class)->modifyItem(['id' => $delayOrder['id'], 'is_reviewed' => 'yes']);
                    }
                }
            }
        });

    }
}

